利用gcc和clang进行多参数包扩展
multiple parameter pack expansion by gcc and clang
我正在尝试使用变量将N
参数函数转换为2^N
参数函数。下面的代码段由clang 3.9
编译得很好,而nvcc 8.0
(实际上是gcc 5.4
)则失败得很惨,并出现错误:
error: no instance of overloaded function "foo" matches the argument list
代码:
template<class... Ts> struct Typelist{};
template <class..., class... Us>
void foo(Typelist<>, Typelist<Us...>, Us... us ){
// do the actual work
}
template <class T, class... Ts, class... Us>
void foo(Typelist<T, Ts...>, Typelist<Us...>, T t, Ts... ts, Us... us){
foo(Typelist<Ts...>{}, Typelist<Us..., Us...>{}
, ts..., us..., (us+t)...);
}
template <class... Ts>
void bar(Ts... ts){
foo(Typelist<Ts...>{}, Typelist<unsigned>{}
, ts..., 0u);
}
称为类似
int main(int /*argc*/, char */*argv*/[])
{
bar(2u);
bar(2u, 3u, 4u);
return 0;
}
我做错什么了吗?如何使用gcc
?
此代码与[temp.dexeract.type]冲突运行:
非推导上下文为:[…]不出现在参数声明列表末尾的函数参数包。
如:
template<class D0, class... Ds, class... Is>
HOST_DEVICE void _apply(Typelist<D0, Ds...> , D0 d0, Ds... ds, Is... is) {
// ~~~~~~~~
和[temp.arg.extical]:
未以其他方式推导的尾随模板参数包(14.5.3)将被推导为模板参数的空序列。
这将非精简包推断为空思想,以不同的方式破坏了gcc和clang上的代码。考虑调用apply(1,2)
:
- 我尝试过的每个版本的gcc都认为
Ds... ds
包是空的,并将Ds...
推导为<int>
,将Is...
推导为<int, unsigned int>
。因此,重载被抛出,因为它需要5个参数,而我们只传递了4个 - 我尝试过的clang的每个版本都从第一个参数中将第二个
Ds...
推导出为<int>
,从包中将<>
推导出,并认为由于不一致性,该推导出失败
不管怎样,这里都没有真正的前进道路。
您可以做的是颠倒顺序,将所有Is...
放在第一位。由于您知道所有类型,因此可以显式指定它们,并让Ds...
被推导出来。即:
template<class... Is>
HOST_DEVICE void _apply(Is..., Typelist<>)
{
// ...
}
template<class... Is, class D0, class... Ds>
HOST_DEVICE void _apply(Is... is, Typelist<D0, Ds...> , D0 d0, Ds... ds) {
_apply<Is..., decltype(std::declval<Is>()+std::declval<D0>())...>(
is...,
(is+d0)...,
Typelist<Ds...>{},
ds...);
}
template<class... Ds>
HOST_DEVICE void apply(Ds... ds) {
_apply<unsigned int>(0u, Typelist<Ds...>{}, ds...);
}
这适用于每个编译器。
所以我对代码进行了一些处理,并提出了3个版本:
在clang中编译,使用gcc:失败
template <class..., class... Us>
void foo(Typelist<>, Typelist<Us...>, Us... us ){ /*do the stuff*/ }
template <class T, class... Ts, class... Us>
void foo(Typelist<T, Ts...>, Typelist<Us...>, T t, Ts... ts, Us... us){
foo(Typelist<Ts...>{}, Typelist<Us..., Us...>{}, ts..., us..., (us+t)...);
}
template <class... Ts>
void bar(Ts... ts){
foo(Typelist<Ts...>{}, Typelist<unsigned>{}, ts..., 0u);
}
有趣的是,这两种类型列表都是工作所必需的,尽管似乎只有一种就足以解决歧义。
下一个是巴里的回答。它使用gcc进行编译,但对我来说,失败的原因是clang:
template<class... Is>
void foo(Is..., Typelist<>) { /*do the stuff*/ }
template<class... Is, class D0, class... Ds>
void foo(Is... is, Typelist<D0, Ds...> , D0 d0, Ds... ds) {
foo<Is..., decltype(std::declval<Is>()+std::declval<D0>())...>(
is...,
(is+d0)...,
Typelist<Ds...>{},
ds...);
}
template<class... Ds>
void bar(Ds... ds) {
foo<unsigned int>(0u, Typelist<Ds...>{}, ds...);
}
最后是一个同时使用gcc(5.4,6.3)和clang(3.9)的:
template<class... Us>
struct foo_impl<Typelist<>, Typelist<Us...>>{
auto operator()(Us... us)-> void { /*do the stuff here*/ }
};
template<class T, class... Ts, class... Us>
struct foo_impl<Typelist<T, Ts...>, Typelist<Us...>>{
auto operator()(T t, Ts... ts, Us... us)-> void{
foo_impl<Typelist<Ts...>, Typelist<Us..., Us...>>{}(ts..., us..., (us+t)...);
}
};
template <class... Ts>
void bar(Ts... ts){
foo_impl<Typelist<Ts...>, Typelist<unsigned>>{}(ts..., 0u);
}
希望有人觉得这很有帮助。
相关文章:
- 嵌套参数包扩展失败
- [temp.variadic]中关于包扩展实例化的措辞
- 模板参数部分中有关包扩展的一些混淆
- 如何使用 std::forward 精确地评估参数包的扩展?
- 参数包没有扩展'...'即使...被使用
- 如何"unzipping"扩展参数包模式?
- 可变参数函数参数包扩展
- c++非类型参数包扩展
- C++别名的模板参数包扩展
- 如何将参数包扩展为向量<any>
- 模板包扩展以将函数应用于连续的参数对
- 模板 使用数据数组调用函数时扩展参数包
- C++参数包扩展
- 如何为原生UI工具包扩展Ranorex?
- 折叠表达式、参数包扩展、类成员函数中的递归
- 将代码移出类定义时未扩展参数包
- xgboost 构建错误:参数包未扩展为"..":
- 可变参数模板:错误:参数包未扩展'...'
- 使用模板包进行扩展
- 使用可变包类型扩展的C++函数调用程序包装