2017-01-30 76 views
1

我試圖用variadics把N參數函數轉換成2^N參數函數。下面的代碼片段通過clang 3.9愉快編譯,而nvcc 8.0(有效gcc 5.4)與錯誤悲慘的失敗了:gcc和clang多參數包擴展

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一起工作?

+1

你在做什麼全面的調用?根本不應該編譯。 – Barry

+0

gcc 6.3.1對此沒有任何問題。 –

+0

@SamVarshavchik真的嗎?這對我來說有一個問題。你有沒有把至少兩個參數傳遞給'apply()'? – Barry

回答

2

此代碼運行的相抵觸[temp.deduct.type]:

The non-deduced contexts are: [...] A function parameter pack that does not occur at the end of the 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]:

A trailing template parameter pack (14.5.3) not otherwise deduced will be deduced to an empty sequence of template arguments.

這種推演 - 非誘惑 - 包裝 - 空想法以不同方式在gcc和clang上破壞你的代碼。考慮呼叫apply(1,2)

  • 每一個版本的gcc我已經試過的考慮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...); 
} 

這適用於每個編譯器。

0

所以我打了一下代碼,並與3個版本想出了:

編譯在鐺,無法用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,但沒有鏗鏘我:

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...); 
} 

最後一個與兩個海灣合作委員會的工作(5.4,6.3)和鐺(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); 
} 

希望有人認爲這很有幫助。