2013-05-21 29 views
7

Đoạn code dưới đây làm việc cho: Mục tiêu cho các hoạt động tổng kết trái: sum(1,2,3,4);mẫu variadic hoạt động tổng kết trái

Tuy nhiên, nó sẽ không hoạt động chính xác cho sum(1,2,3,4,5) hoặc sum(1,2,3,4,5,...). Bất kỳ điều gì có hơn 4 đối số đều có lỗi:

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

tôi đoán là nó không thể evauluate tổng sử dụng mẫu varidic recursivly trước khi nó được decleared người. Tôi không có đầu mối mặc dù làm thế nào để giải quyết nó. Không thể nào? – Xale

+0

Tôi có thể tạo lại vấn đề đó trên gcc 4.7.2: http://ideone.com/6X4f2b - có vẻ như gcc từ chối gọi các mẫu variadic với các kiểu trả về tự động/từ chối một cách đệ quy. –

+1

Xem [link] [1] này. Gần câu hỏi giống hệt nhau. [1]: http://stackoverflow.com/questions/3744400/trailing-return-type-using-decltype-with-a-variadic-template-function – Xale

Trả lời

5

Điều đó có vẻ là một lỗi trong GCC, khi làm việc với các mẫu variadic, các kiểu trả về tự động và tham chiếu đệ quy đến cùng một mẫu variadic trong kiểu trả về theo sau.

Đó là khả năng giải quyết, thông qua mẫu cũ lập trình meta tốt:

//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: để thậm chí còn chung chung hơn, toàn bộ điều có thể được pimped với "tài liệu tham khảo phổ thông" và std::forward.

Cập nhật: sử dụng std::declval thay vì chức năng viết tay

+5

'std :: declval ()' là chính xác stand-in cho 'T()' bên trong của decltype. – Xeo

+0

là phải có từ khóa "tự động" trước số tiền (const T1 & v1, const Ts & ... phần còn lại) – Alper

+0

Cảm ơn các nhận xét, đã cải thiện cả hai điểm. –

1

Chức năng cần thêm kiểm tra:

#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; 
} 

và nó vượt qua tốt hơn bởi giá trị.

nếu không chúng tôi có thể nhận được kết quả kỳ lạ:

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


return 0; 
} 
Các vấn đề liên quan