应用具有多个模板参数包的 CTAD
Applying CTAD with multiple template parameter packs
按照此处提供的一些解决方案 How can I have multiple parameter packs in a variadic template?,我希望将多个参数包应用于 classes 并使用 CTAD 使 class 更有用。
这是我想出的(在 Coliru 上),但这给出了:
error: class template argument deduction failed
这是我试过的代码:
// A template to hold a parameter pack
template < typename... >
struct Typelist {};
// Declaration of a template
template< typename TypeListOne
, typename TypeListTwo
>
struct Foo;
// A template to hold a parameter pack
template <typename... Args1, typename... Args2>
struct Foo< Typelist < Args1... >
, Typelist < Args2... >
>{
template <typename... Args>
struct Bar1{
Bar1(Args... myArgs) {
_t = std::make_tuple(myArgs...);
}
std::tuple<Args...> _t;
};
template <typename... Args>
struct Bar2{
Bar2(Args... myArgs) {
_t = std::make_tuple(myArgs...);
}
std::tuple<Args...> _t;
};
Bar1<Args1...> _b1;
Bar2<Args2...> _b2;
Foo(Bar1<Args1...>& b1, Bar2<Args2...>& b2) {
_b1 = b1;
_b2 = b2;
}
};
int main()
{
Foo{Foo::Bar1(1, 2.0, 3), Foo::Bar2(100, 23.4, 45)};
return 0;
}
首先,CTAD 在使用范围解析运算符时没有完成,因此永远不能使用 Foo::
。您必须明确指定此 Foo
的模板参数。
我建议您只需将 Bar1
和 Bar2
移动到 Foo
部分特化之外的命名空间范围内并使用
Foo{Bar1(1, 2.0, 3), Bar2(100, 23.4, 45)};
相反。
然后你会得到一个错误,Foo
的推导失败。这是因为只有 primary 模板中的构造函数才被考虑用于隐式推导指南。但是您要使用的构造函数在部分特化中,而不是主模板中。
所以你需要自己添加一个合适的推导指南,例如:
template <typename... Args1, typename... Args2>
Foo(Bar1<Args1...>, Bar2<Args2...>) -> Foo<Typelist<Args1...>, Typelist<Args2...>>;
然后你会得到一个错误,说没有构造函数是可行的。这是因为您将 Bar1<Args1...>& b1
和 Bar2<Args2...>& b2
作为非 const
左值引用,但您为它们提供了纯右值。非 const
左值引用无法绑定到右值,因此会出现错误。按值或按 const
左值引用获取参数。
最后会报错_b1
和_b2
没有默认构造函数,这是真的。它们是必需的,因为您在构造函数中默认初始化 _b1
和 _b2
。您只能稍后为它们赋值。
因此,要么将默认构造函数添加到 Bar1
和 Bar2
,要么更好地使用初始化而不是赋值:
Foo(const Bar1<Args1...>& b1, const Bar2<Args2...>& b2) : _b1(b1), _b2(b2) { }
完成所有这些步骤后,代码应该可以编译。我不确定 您的目标到底是什么,因此不能完全确定这是否会达到您的要求。
按照此处提供的一些解决方案 How can I have multiple parameter packs in a variadic template?,我希望将多个参数包应用于 classes 并使用 CTAD 使 class 更有用。
这是我想出的(在 Coliru 上),但这给出了:
error: class template argument deduction failed
这是我试过的代码:
// A template to hold a parameter pack
template < typename... >
struct Typelist {};
// Declaration of a template
template< typename TypeListOne
, typename TypeListTwo
>
struct Foo;
// A template to hold a parameter pack
template <typename... Args1, typename... Args2>
struct Foo< Typelist < Args1... >
, Typelist < Args2... >
>{
template <typename... Args>
struct Bar1{
Bar1(Args... myArgs) {
_t = std::make_tuple(myArgs...);
}
std::tuple<Args...> _t;
};
template <typename... Args>
struct Bar2{
Bar2(Args... myArgs) {
_t = std::make_tuple(myArgs...);
}
std::tuple<Args...> _t;
};
Bar1<Args1...> _b1;
Bar2<Args2...> _b2;
Foo(Bar1<Args1...>& b1, Bar2<Args2...>& b2) {
_b1 = b1;
_b2 = b2;
}
};
int main()
{
Foo{Foo::Bar1(1, 2.0, 3), Foo::Bar2(100, 23.4, 45)};
return 0;
}
首先,CTAD 在使用范围解析运算符时没有完成,因此永远不能使用 Foo::
。您必须明确指定此 Foo
的模板参数。
我建议您只需将 Bar1
和 Bar2
移动到 Foo
部分特化之外的命名空间范围内并使用
Foo{Bar1(1, 2.0, 3), Bar2(100, 23.4, 45)};
相反。
然后你会得到一个错误,Foo
的推导失败。这是因为只有 primary 模板中的构造函数才被考虑用于隐式推导指南。但是您要使用的构造函数在部分特化中,而不是主模板中。
所以你需要自己添加一个合适的推导指南,例如:
template <typename... Args1, typename... Args2>
Foo(Bar1<Args1...>, Bar2<Args2...>) -> Foo<Typelist<Args1...>, Typelist<Args2...>>;
然后你会得到一个错误,说没有构造函数是可行的。这是因为您将 Bar1<Args1...>& b1
和 Bar2<Args2...>& b2
作为非 const
左值引用,但您为它们提供了纯右值。非 const
左值引用无法绑定到右值,因此会出现错误。按值或按 const
左值引用获取参数。
最后会报错_b1
和_b2
没有默认构造函数,这是真的。它们是必需的,因为您在构造函数中默认初始化 _b1
和 _b2
。您只能稍后为它们赋值。
因此,要么将默认构造函数添加到 Bar1
和 Bar2
,要么更好地使用初始化而不是赋值:
Foo(const Bar1<Args1...>& b1, const Bar2<Args2...>& b2) : _b1(b1), _b2(b2) { }
完成所有这些步骤后,代码应该可以编译。我不确定 您的目标到底是什么,因此不能完全确定这是否会达到您的要求。