使用 class 个模板对可变参数模板进行专业化
specialization of variadic templates with class templates
这是我在使用可变参数模板时 运行 遇到的一个问题。我有一些代码使用专门化来计算参数包中的 "interesting" 类型,如下所示:
template<typename... _Pp>
struct count;
template<>
struct count<>
{
static const int value = 0;
};
// ignore uninteresting types
template<typename _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = count<_Rest...>::value;
};
// add 1 for a pointer
template<typename _First, typename... _Rest>
struct count<_First*, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for a reference
template<typename _First, typename... _Rest>
struct count<_First&, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for an int
template<typename... _Rest>
struct count<int, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
这段代码工作正常,但如果我想使用相同的方法来计算 class 个模板,我 运行 就会遇到问题:
// add 1 for a vector
template<typename... _Rest>
struct count<vector, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
以上代码编译失败,错误是"struct count"开头的行"expected a type, got 'vector'"。我也无法做到更简单的事情,所有 class 模板都接受一个参数:
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
}
此代码也无法编译,在以 "struct count" 开头的行再次抱怨 "expected a type, got '_First'"。是否有人熟悉使用这种方法实现此目标的方法(即我可以对一个或两个特化进行一些修改,使它们在编译时编译并执行所需的计算)?
编辑:
我希望 vector 的参数包未绑定,类似于以下代码,用于具有可变参数模板模板参数的简单容器包装器,该参数也专门用于 std::vector:
// pass a container as a parameter using variadic template-template
parameter
template<typename _Tp, template<typename...> class _C>
struct success
{
// not specialized for any container
static const bool is_specialized = false;
// data member of container type
_C<_Tp> c_;
};
// partial specialization of above for std::vector
template<typename _Tp>
struct success<_Tp, std::vector>
{
// specialized for vector
static const bool is_specialized = true;
// again, data member of container type
std::vector<_Tp> c_;
};
编辑
似乎最终的答案是我想做的事情无法完成,但我找到了一种方法来重构问题,以便我可以解决它。非常感谢那些提供帮助的人。
这样的怎么样?
// add 1 for a vector
template<typename... _Rest, typename T>
struct count<vector<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
还有这个?
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename T, typename... _Rest>
struct count<_First<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
应该是:
template<typename... _Rest, typename... T>
struct count<std::vector<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
通用版本:
template<template<typename...> class C, typename... _Rest, typename... T>
struct count<C<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
可变参数包很重要。
如果我理解正确你想要什么...是的,你可以创建一个可以计数的模板化结构"class templates",这样你就可以写类似
的东西
count<std::vector, std::map, std::set, std::pair>::value
但是你不能混合使用 class 模板和简单的类型名,所以你不能写类似
的东西
count<std::vector, int &, float, std::set>::value
问题是如果你定义
template <typename... _Pp>
struct count;
你可以传递 std::vector<int>
给它,因为 std::vector<int>
是一个 typename
,但是你不能传递 std::vector
给它,因为 std::vector
不是'不是typename
;这是一个 template<typename...> class
(或模板模板),它是完全不同的东西。
你可以这样写struct countC
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
以下是一个完整的工作示例,其中我将您的 struct count
重写为 struct countT
以计算所选类型,我添加了 struct countC
以计算所选类型 "class templates" 并且我添加了 struct countV
来计算固定类型名称的选定值。
#include <map>
#include <set>
#include <vector>
#include <utility>
#include <iostream>
// countC for templates
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::map, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::pair, R...>
{ static const int value = 1 + countC<R...>::value; };
// countV for for values of a fixed type
template <typename T, T ... v>
struct countV;
template <typename T>
struct countV<T>
{ static const int value = 0; };
// ignore uninteresting values
template <typename T, T f, T ... r>
struct countV<T, f, r...>
{ static const int value = countV<T, r...>::value; };
// count only int odd values
template <int f, int ... r>
struct countV<int, f, r...>
{ static const int value = (f % 2) + countV<int, r...>::value; };
// countT for typenames
template <typename...>
struct countT;
template <>
struct countT<>
{ static const int value = 0; };
// ignore uninteresting types
template <typename F, typename ... R>
struct countT<F, R...>
{ static const int value = countT<R...>::value; };
template <typename F, typename ... R>
struct countT<F*, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename F, typename ... R>
struct countT<F&, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename ... R>
struct countT<int, R...>
{ static const int value = 1 + countT<R...>::value; };
int main()
{
std::cout << "countC vector + map + set + pair = "
<< countC<std::vector, std::map, std::set, std::pair>::value
<< std::endl;
std::cout << "countT int + float + bool* + double& + bool + int& = "
<< countT<int, float, bool*, double&, bool, int&>::value
<< std::endl;
std::cout << "countV int, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<int, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
std::cout << "countV long, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<long, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
return 0;
}
p.s.: 对不起我的英语不好
这是我在使用可变参数模板时 运行 遇到的一个问题。我有一些代码使用专门化来计算参数包中的 "interesting" 类型,如下所示:
template<typename... _Pp>
struct count;
template<>
struct count<>
{
static const int value = 0;
};
// ignore uninteresting types
template<typename _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = count<_Rest...>::value;
};
// add 1 for a pointer
template<typename _First, typename... _Rest>
struct count<_First*, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for a reference
template<typename _First, typename... _Rest>
struct count<_First&, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for an int
template<typename... _Rest>
struct count<int, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
这段代码工作正常,但如果我想使用相同的方法来计算 class 个模板,我 运行 就会遇到问题:
// add 1 for a vector
template<typename... _Rest>
struct count<vector, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
以上代码编译失败,错误是"struct count"开头的行"expected a type, got 'vector'"。我也无法做到更简单的事情,所有 class 模板都接受一个参数:
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
}
此代码也无法编译,在以 "struct count" 开头的行再次抱怨 "expected a type, got '_First'"。是否有人熟悉使用这种方法实现此目标的方法(即我可以对一个或两个特化进行一些修改,使它们在编译时编译并执行所需的计算)?
编辑: 我希望 vector 的参数包未绑定,类似于以下代码,用于具有可变参数模板模板参数的简单容器包装器,该参数也专门用于 std::vector:
// pass a container as a parameter using variadic template-template
parameter
template<typename _Tp, template<typename...> class _C>
struct success
{
// not specialized for any container
static const bool is_specialized = false;
// data member of container type
_C<_Tp> c_;
};
// partial specialization of above for std::vector
template<typename _Tp>
struct success<_Tp, std::vector>
{
// specialized for vector
static const bool is_specialized = true;
// again, data member of container type
std::vector<_Tp> c_;
};
编辑 似乎最终的答案是我想做的事情无法完成,但我找到了一种方法来重构问题,以便我可以解决它。非常感谢那些提供帮助的人。
这样的怎么样?
// add 1 for a vector
template<typename... _Rest, typename T>
struct count<vector<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
还有这个?
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename T, typename... _Rest>
struct count<_First<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
应该是:
template<typename... _Rest, typename... T>
struct count<std::vector<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
通用版本:
template<template<typename...> class C, typename... _Rest, typename... T>
struct count<C<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
可变参数包很重要。
如果我理解正确你想要什么...是的,你可以创建一个可以计数的模板化结构"class templates",这样你就可以写类似
的东西 count<std::vector, std::map, std::set, std::pair>::value
但是你不能混合使用 class 模板和简单的类型名,所以你不能写类似
的东西 count<std::vector, int &, float, std::set>::value
问题是如果你定义
template <typename... _Pp>
struct count;
你可以传递 std::vector<int>
给它,因为 std::vector<int>
是一个 typename
,但是你不能传递 std::vector
给它,因为 std::vector
不是'不是typename
;这是一个 template<typename...> class
(或模板模板),它是完全不同的东西。
你可以这样写struct countC
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
以下是一个完整的工作示例,其中我将您的 struct count
重写为 struct countT
以计算所选类型,我添加了 struct countC
以计算所选类型 "class templates" 并且我添加了 struct countV
来计算固定类型名称的选定值。
#include <map>
#include <set>
#include <vector>
#include <utility>
#include <iostream>
// countC for templates
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::map, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::pair, R...>
{ static const int value = 1 + countC<R...>::value; };
// countV for for values of a fixed type
template <typename T, T ... v>
struct countV;
template <typename T>
struct countV<T>
{ static const int value = 0; };
// ignore uninteresting values
template <typename T, T f, T ... r>
struct countV<T, f, r...>
{ static const int value = countV<T, r...>::value; };
// count only int odd values
template <int f, int ... r>
struct countV<int, f, r...>
{ static const int value = (f % 2) + countV<int, r...>::value; };
// countT for typenames
template <typename...>
struct countT;
template <>
struct countT<>
{ static const int value = 0; };
// ignore uninteresting types
template <typename F, typename ... R>
struct countT<F, R...>
{ static const int value = countT<R...>::value; };
template <typename F, typename ... R>
struct countT<F*, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename F, typename ... R>
struct countT<F&, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename ... R>
struct countT<int, R...>
{ static const int value = 1 + countT<R...>::value; };
int main()
{
std::cout << "countC vector + map + set + pair = "
<< countC<std::vector, std::map, std::set, std::pair>::value
<< std::endl;
std::cout << "countT int + float + bool* + double& + bool + int& = "
<< countT<int, float, bool*, double&, bool, int&>::value
<< std::endl;
std::cout << "countV int, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<int, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
std::cout << "countV long, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<long, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
return 0;
}
p.s.: 对不起我的英语不好