如何在一个可变模板中拥有多个参数包
How can I have multiple parameter packs in a variadic template?
函数one()接受一个参数包。函数two()接受两个。每个包都被限制为封装在类型A和B中。为什么不可能实例化two()?
template <typename T>
struct A {};
template <typename T>
struct B {};
template <typename... Ts>
void one(A<Ts> ...as) {
}
template <typename... Ts, typename... Us>
void two(A<Ts> ...as, B<Us> ...bs) {
}
int main() {
auto a = A<int>();
auto b = B<int>();
// Just fine
one();
one(a);
one(a, a);
// All errors
two();
two(a);
two(a, b);
}
尝试使用gcc和clang。
sam@wish:~/x/cpp$ gcc -std=c++0x variadic_templates.cpp
variadic_templates.cpp: In function ‘int main()’:
variadic_templates.cpp:23:7: error: no matching function for call to ‘two()’
variadic_templates.cpp:23:7: note: candidate is:
variadic_templates.cpp:11:6: note: template<class ... Ts, class ... Us> void two(A<Ts>..., B<Us>...)
variadic_templates.cpp:24:8: error: no matching function for call to ‘two(A<int>&)’
variadic_templates.cpp:24:8: note: candidate is:
variadic_templates.cpp:11:6: note: template<class ... Ts, class ... Us> void two(A<Ts>..., B<Us>...)
variadic_templates.cpp:25:11: error: no matching function for call to ‘two(A<int>&, B<int>&)’
variadic_templates.cpp:25:11: note: candidate is:
variadic_templates.cpp:11:6: note: template<class ... Ts, class ... Us> void two(A<Ts>..., B<Us>...)
sam@wish:~/x/cpp$ clang -std=c++0x variadic_templates.cpp
variadic_templates.cpp:23:3: error: no matching function for call to 'two'
two();
^~~
variadic_templates.cpp:11:6: note: candidate function template not viable: requires at least 1 argument, but 0 were provided
void two(A<Ts> ...as, B<Us> ...bs) {}
^
variadic_templates.cpp:24:3: error: no matching function for call to 'two'
two(a);
^~~
variadic_templates.cpp:11:6: note: candidate function not viable: requires 0 arguments, but 1 was provided
void two(A<Ts> ...as, B<Us> ...bs) {}
^
variadic_templates.cpp:25:3: error: no matching function for call to 'two'
two(a, b);
^~~
variadic_templates.cpp:11:6: note: candidate function not viable: requires 0 arguments, but 2 were provided
void two(A<Ts> ...as, B<Us> ...bs) {}
^
3 errors generated.
以下是使用模板模板参数获得多个参数包的另一种方法:
#include <iostream>
template <typename... Types>
struct foo {};
template < typename... Types1, template <typename...> class T
, typename... Types2, template <typename...> class V
, typename U >
void
bar(const T<Types1...>&, const V<Types2...>&, const U& u)
{
std::cout << sizeof...(Types1) << std::endl;
std::cout << sizeof...(Types2) << std::endl;
std::cout << u << std::endl;
}
int
main()
{
foo<char, int, float> f1;
foo<char, int> f2;
bar(f1, f2, 9);
return 0;
}
我找到了一个解决方案。将每个参数包包裹在一个元组中。使用结构进行部分专门化。这里有一个演示,通过将一个元组作为列表并累积另一个元组,将参数转发到函子。好吧,这个是通过复制转发的。元组用于类型推导,但函数参数中没有使用元组,我认为这很巧妙。
#include <iostream>
#include <tuple>
template < typename ... >
struct two_impl {};
// Base case
template < typename F,
typename ...Bs >
struct two_impl < F, std::tuple <>, std::tuple< Bs... > > {
void operator()(F f, Bs... bs) {
f(bs...);
}
};
// Recursive case
template < typename F,
typename A,
typename ...As,
typename ...Bs >
struct two_impl < F, std::tuple< A, As... >, std::tuple< Bs...> > {
void operator()(F f, A a, As... as, Bs... bs) {
auto impl = two_impl < F, std::tuple < As... >, std::tuple < Bs..., A> >();
impl(f, as..., bs..., a);
}
};
template < typename F, typename ...Ts >
void two(F f, Ts ...ts) {
auto impl = two_impl< F, std::tuple < Ts... >, std::tuple <> >();
impl(f, ts...);
}
struct Test {
void operator()(int i, float f, double d) {
std::cout << i << std::endl << f << std::endl << d << std::endl;
}
};
int main () {
two(Test(), 1, 1.5f, 2.1);
}
元组是一个非常好的编译时列表。
如果模板参数包后面的每个模板参数都有默认值或可以推导,则函数模板(如skypjack的示例)以及类和变量模板的部分专门化可以具有多个参数包。我唯一想补充/指出的是,对于类和变量模板,您需要部分专业化。(参见:C++模板,完整指南,Vandevoorde,Josuttis,Gregor 12.2.4,第二版)
// A template to hold a parameter pack
template < typename... >
struct Typelist {};
// Declaration of a template
template< typename TypeListOne
, typename TypeListTwo
>
struct SomeStruct;
// Specialization of template with multiple parameter packs
template< typename... TypesOne
, typename... TypesTwo
>
struct SomeStruct< Typelist < TypesOne... >
, Typelist < TypesTwo... >
>
{
// Can use TypesOne... and TypesTwo... how ever
// you want here. For example:
typedef std::tuple< TypesOne... > TupleTypeOne;
typedef std::tuple< TypesTwo... > TupleTypeTwo;
};
编译器需要一种方法来知道两个可变模板之间的屏障在哪里。一个干净的方法是为对象定义一组参数,为静态成员函数定义第二组参数。这可以通过在彼此中嵌套多个结构来应用于两个以上的可变模板。(保持最后一级功能)
#include <iostream>
template<typename... First>
struct Obj
{
template<typename... Second>
static void Func()
{
std::cout << sizeof...(First) << std::endl;
std::cout << sizeof...(Second) << std::endl;
}
};
int main()
{
Obj<char, char>::Func<char, char, char, char>();
return 0;
}
two<>();
two<int>(a);
two<int>(a, b);
参见https://www.youtube.com/watch?v=va9I2qivBOA29:00-35:00
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 是否可以获取成员函数模板参数的拥有对象?
- 在C++中,有没有一种方法可以让我在不传递参数的情况下拥有一个函数
- 当超出列时,clang格式强制每个参数/参数拥有自己的行?
- 如何有效地传递 std::vector<cv::P oint3f> 的子向量作为参数(不拥有函数)
- 如何拥有具有类型和大小的可变参数模板
- 如何拥有多个参数包
- open() 的参数:每个人都应该拥有对文件的所有访问权限,并且应该在创建时被截断
- 朋友拥有自己的类模板和其他模板参数
- 如何定义它可以拥有任意参数的模板类
- 如何拥有一个带有类元素的向量,其中一些元素分配了构造函数参数
- 如何在一个可变模板中拥有多个参数包
- Doxygen:是否可以对C++函数参数进行分组,即在不复制的情况下拥有相同的文档
- C++可以拥有一个包含不同类型参数的专用模板对象的容器
- MSXML方法是否对其BSTR参数拥有内存所有权?