计算嵌套包中的类型总数
Counting the total number of types in a nested pack
NumTypes<Args...>::value
是给出Args...
中类型的总数,包括嵌套包中的所有类型(如果有的话),例如如果
using T = Group<int, bool, Wrap<char, Pack<char, long, Group<char, Object, short>, short>, double>, long>;
然后 NumTypes<T, int, char>::value
将是 13(我们不计算包装器 类 本身)。下面的代码工作正常,但是当我用 std::string
替换任何类型时,我得到一连串的 std::allocator
错误,这些错误永远不会终止(使用 GCC 4.8.1)。我怀疑其他类型会产生相同的错误。为什么?以及如何修复代码以避免出现这种奇怪的错误?
#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
是 std::basic_string<char>
的 typedef,因此匹配 IsPack
和 NumTypes
的特化,用于分组类型。
您必须专注于分组或模板叶类型,在您的情况下,以更省力的方式为准:
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
}
std::string
实际上是 std::basic_string<char, char_traits<char>, allocator<charT>>
.
它的声明有默认的模板参数:
template <class charT,
class traits = char_traits<charT>,
class Alloc = allocator<charT>>
class basic_string;
你的递归是如此错误,而且你有无限循环(当你从 basic_string<charT, traits, Alloc>
中删除第一个参数时,你得到 basic_string<traits, Alloc, allocator<traits>>
)。
您可以通过从等式中删除 P
来解决这个问题:
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;
};
NumTypes<Args...>::value
是给出Args...
中类型的总数,包括嵌套包中的所有类型(如果有的话),例如如果
using T = Group<int, bool, Wrap<char, Pack<char, long, Group<char, Object, short>, short>, double>, long>;
然后 NumTypes<T, int, char>::value
将是 13(我们不计算包装器 类 本身)。下面的代码工作正常,但是当我用 std::string
替换任何类型时,我得到一连串的 std::allocator
错误,这些错误永远不会终止(使用 GCC 4.8.1)。我怀疑其他类型会产生相同的错误。为什么?以及如何修复代码以避免出现这种奇怪的错误?
#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
是 std::basic_string<char>
的 typedef,因此匹配 IsPack
和 NumTypes
的特化,用于分组类型。
您必须专注于分组或模板叶类型,在您的情况下,以更省力的方式为准:
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
}
std::string
实际上是 std::basic_string<char, char_traits<char>, allocator<charT>>
.
它的声明有默认的模板参数:
template <class charT,
class traits = char_traits<charT>,
class Alloc = allocator<charT>>
class basic_string;
你的递归是如此错误,而且你有无限循环(当你从 basic_string<charT, traits, Alloc>
中删除第一个参数时,你得到 basic_string<traits, Alloc, allocator<traits>>
)。
您可以通过从等式中删除 P
来解决这个问题:
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;
};