我正在尝试使用variadics将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
一起使用?
答案 0 :(得分:2)
此代码与[temp.deduct.type]:
发生冲突非推断的上下文是:[...]一个函数参数包,它不会出现在 parameter-declaration-list 的末尾。
如:
template<class D0, class... Ds, class... Is>
HOST_DEVICE void _apply(Typelist<D0, Ds...> , D0 d0, Ds... ds, Is... is) {
// ~~~~~~~~
和[temp.arg.explicit]:
未以其他方式推导出的尾随模板参数包(14.5.3)将被推导为空的模板参数序列。
这种演绎 - 非诱导包装为空的想法会以不同的方式破坏你在gcc和clang上的代码。考虑通话apply(1,2)
:
Ds... ds
包为空,并将Ds...
推断为<int>
,将Is...
推断为<int, unsigned int>
。所以超载被抛出,因为它需要5个参数,而我们只传递4个。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...);
}
这适用于每个编译器。
答案 1 :(得分:0)
所以我玩了一些代码并提出了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);
}
有趣的是,这两种类型列表都是必需的,尽管似乎只有一种类型可以解决歧义。
接下来是Barry的回答。它用gcc编译,但对我来说却失败了:
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);
}
希望有人觉得这很有帮助。