NumTypes<Args...>::value
is to give the total number of types in Args...
, including all types in a nested packs (if any), eg if
using T = Group<int, bool, Wrap<char, Pack<char, long, Group<char, Object, short>, short>, double>, long>;
then NumTypes<T, int, char>::value
will be 13 (we do not count the wrapper classes themselves). The following code works correctly, but when I replace any of the types with std::string
I get a flurry of std::allocator
errors that never terminates (with GCC 4.8.1). I suspect other types will generate the same error. Why? And how to fix the code to avoid this weird error?
#include <iostream>
#include <string>
#define show(variable) std::cout << #variable << " = " << variable << std::endl;
template <typename T>
struct IsPack {
static const bool value = false;
};
template <template <typename...> class P, typename... Args>
struct IsPack<P<Args...>> {
static const bool value = true;
};
template <typename...> struct NumTypes;
template <typename T>
struct NumTypes<T> {
static const int value = 1;
};
template <template <typename...> class P>
struct NumTypes<P<>> { static const int value = 0; };
template <template <typename...> class P, typename First, typename... Rest>
struct NumTypes<P<First, Rest...>> {
static const int value = IsPack<First>::value ?
NumTypes<First>::value + NumTypes<P<Rest...>>::value :
1 + NumTypes<P<Rest...>>::value;
};
template <typename First, typename... Rest>
struct NumTypes<First, Rest...> {
static const int value = NumTypes<First>::value + NumTypes<Rest...>::value;
};
template <typename...> struct Pack;
template <typename...> struct Group;
template <typename...> struct Wrap;
struct Object {};
int main() {
using A = Pack<int, Object, long>;
show (NumTypes<A>::value) // 3
using B = Pack<int, bool, Pack<char, Object>, long>;
show (NumTypes<B>::value) // 5
using C = Group<int, bool, Wrap<char, Pack<char, long, Group<char, Object, short>, short>, double>, long>;
show (NumTypes<C>::value) // 11
using D = Group<Pack<int, Object, double>, bool, Wrap<char, Pack<char, double, Group<char, Pack<char, long, short>, int, Object>, short>, double>, long>;
show (NumTypes<D>::value) // 16
std::cout << NumTypes<A, B, int, char, C, Object, D>::value << std::endl; // 38
}
std::string
is in fact std::basic_string<char, char_traits<char>, allocator<charT>>
.
And its declaration has default template argument:
template <class charT,
class traits = char_traits<charT>,
class Alloc = allocator<charT>>
class basic_string;
Your recursion is so wrong, And you have infinite loop (when you remove the first parameter from basic_string<charT, traits, Alloc>
, you got basic_string<traits, Alloc, allocator<traits>>
).
You may fix that by removing P
from the equation:
template <template <typename...> class P, typename First, typename... Rest>
struct NumTypes<P<First, Rest...>> {
static const int numInFirst = NumTypes<First>::value;
static const int value = numInFirst + NumTypes<std::tuple<Rest...>>::value;
};
std::string
is a typedef for std::basic_string<char>
, and thus matches specializations of IsPack
and NumTypes
you intended for grouping types.
You'll have to specialize either for grouping or template leaf types, whichever'll take less effort in your case:
template <typename T>
struct IsPack
: std::false_type
{};
template <typename...>
struct NumTypes;
template <typename T, bool is_pack>
struct NumTypesHelper;
template <typename T>
struct NumTypesHelper<T, false>
: std::integral_constant<int, 1>
{};
template <template <typename...> class P, typename... Args>
struct NumTypesHelper<P<Args...>, true>
: NumTypes<Args...>
{};
template <>
struct NumTypes<>
: std::integral_constant<int, 0>
{};
template <typename First, typename... Rest>
struct NumTypes<First, Rest...>
: std::integral_constant<int, NumTypesHelper<First, IsPack<First>::value>::value + NumTypes<Rest...>::value>
{};
template <typename...> struct Pack;
template <typename...> struct Group;
template <typename...> struct Wrap;
struct Object {};
template <typename... Args>
struct IsPack<Pack<Args...>>
: std::true_type
{};
template <typename... Args>
struct IsPack<Group<Args...>>
: std::true_type
{};
template <typename... Args>
struct IsPack<Wrap<Args...>>
: std::true_type
{};
#define show(variable) std::cout << #variable << " = " << variable << std::endl;
int main() {
using A = Pack<int, Object, long>;
show (NumTypes<A>::value) // 3
using B = Pack<int, bool, Pack<char, double>, long>;
show (NumTypes<B>::value) // 5
using C = Group<int, bool, Wrap<char, Pack<char, long, Group<char, Object, short>, short>, double>, long>;
show (NumTypes<C>::value) // 11
using D = Group<Pack<int, Object, double>, bool, Wrap<char, Pack<char, double, Group<char, Pack<char, long, short>, int, Object>, short>, double>, long>;
show (NumTypes<D>::value) // 16
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.