2013-05-21 30 views
7

下面的代碼工作爲:目標,左聯和操作:sum(1,2,3,4);可變參數模板和操作左關聯

但是,它不會正確的sum(1,2,3,4,5)sum(1,2,3,4,5,...)工作。任何超過4個參數給出了錯誤:

error: no matching function for call to sum(int, int, int, int, int)

=================================

template <typename T> 
T sum(const T& v) { 
return v; 
} 

template <typename T1, typename T2> 
auto sum(const T1& v1, const T2& v2) -> decltype(v1 + v2) { 
return v1 + v2; 
} 

template <typename T1, typename T2, typename... Ts> 
auto sum(const T1& v1, const T2& v2, const Ts&... rest) -> decltype(v1 + v2 +  sum(rest...)) { 
return v1 + v2 + sum(rest...); 
} 

int main() { 
    cout << sum(1,2,3,4); //works correctly 
    //cout << sum(1,2,3,4,5); //compile error 

} 
+0

我的猜測是,它可以不使用recursivly之前,decleared那些varidic模板evauluate的總和。我不知道如何解決它。不可能? – Xale

+0

我可以在gcc 4.7.2上重現該問題:http://ideone.com/6X4f2b - 似乎gcc拒絕以遞歸方式使用auto/decltype返回類型調用可變參數模板。 –

+1

看到這個[鏈接] [1]。接近相同的問題。 [1]:http://stackoverflow.com/questions/3744400/trailing-return-type-using-decltype-with-a-variadic-template-function – Xale

回答

5

這似乎是在GCC的一個bug,用可變參數模板,自動返回類型和遞歸參考尾隨返回類型相同的可變參數模板工作時。

它是可以解決的,通過良好的舊模板元編程:

//first a metafunction to calculate the result type of sum(Ts...) 
template <typename...> struct SumTs; 
template <typename T1> struct SumTs<T1> { typedef T1 type; }; 
template <typename T1, typename... Ts> 
struct SumTs<T1, Ts...> 
{ 
    typedef typename SumTs<Ts...>::type rhs_t; 
    typedef decltype(std::declval<T1>() + std::declval<rhs_t>()) type; 
}; 

//now the sum function 
template <typename T> 
T sum(const T& v) { 
    return v; 
} 

template <typename T1, typename... Ts> 
auto sum(const T1& v1, const Ts&... rest) 
    -> typename SumTs<T1,Ts...>::type //instead of the decltype 
{ 
    return v1 + sum(rest...); 
} 

#include <iostream> 
using std::cout; 

int main() { 
    cout << sum(1,2,3,4,5);  
} 

PS:要更加通用的,整個事情可以用「通用引用」和拉皮條std::forward

更新:使用std::declval代替手寫功能

+5

'std :: declval ()'是decltype內部'T()'的正確替身。 – Xeo

+0

在 sum(const T1&v1,const TS&... rest)前面必須有「auto」關鍵字 – Alper

+0

感謝您的意見,改進了這兩點。 –

1

功能需要額外的檢查:

#include <type_traits> 

template <typename T> 
T sum(T v) 
{ 
    static_assert(std::is_arithmetic<std::remove_reference<decltype(v)>::type>::value, 
    "type should be arithmetic"); 
    return v; 
} 

,它是按值傳遞越好。

否則我們可以得到奇怪的結果:

int main() { 
std::cout << sum(1,"Hello World"); 


return 0; 
}