2012-10-28 29 views
10

Giả mã sau:quá tải bất ngờ gọi khi hàm được gọi từ mẫu variadic instantiation

#include <iostream> 

template<typename... T> 
void foo(const T &...); 

template<unsigned N> 
void foo(const char (&)[N]) 
{ 
    std::cout << "char(&)[N]" << std::endl; 
} 

void foo(const char *) 
{ 
    std::cout << "const char *" << std::endl; 
} 

template<typename T> 
void foo(const T &) 
{ 
    std::cout << "Single" << std::endl; 
} 

template<typename First, typename... T> 
void foo(const First & first, const T &... rest) 
{ 
    std::cout << "Generic + " << sizeof...(T) << std::endl; 
    foo(first); 
    foo(rest...); 
} 

int main() 
{ 
    const char * c = "asdf"; 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo('f', c, a, 1); 
    foo(a); 
} 

The output is:

Generic + 3 
Single    // fine; 'f' is `char` -> generic 
Generic + 2 
const char *  // fine; c is `const char *` 
Generic + 1 
const char *  // (!) not fine 
Single 
char(&)[N]   // fine; a is char[4] 

Cuộc gọi cuối cùng - foo(a), nơi achar[4] - gọi là phiên bản tôi mong đợi - template<unsigned N> void foo(const char (&)[N]). Nhưng tại sao không mô phỏng mẫu variadic của foo gọi foo(const char (&)[N], nhưng thay vào đó hãy gọi foo(const char *)? Nếu không có quá tải mảng char, điều đó sẽ được mong đợi - nhưng tại sao nó lại xảy ra ở đây? Không nên const First & chụp loại mảng đúng cách?

Ngoài ra, cách dễ nhất để làm cho phiên bản variadic chung hoạt động đúng với các mảng được truyền cho nó là gì?


Như Matthieu M. nhận thấy trong các ý kiến, vấn đề có lẽ không phải là do mẫu variadic, nhưng bởi indirection:

#include <iostream> 

template <unsigned N> 
void foo(const char (&)[N]) 
{ 
    std::cout << "char(&)[N]" << std::endl; 
} 

void foo(const char *) 
{ 
    std::cout << "const char *" << std::endl; 
} 

template <typename T> 
void goo(T const& t) { 
    foo(t); 
} 

int main() 
{ 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo(a); 
    goo(a); 
} 
 
    char(&)[N] 
    const char * 

Ông cũng nói rằng nó có thể là trình biên dịch bug - mặc dù mã này mang lại kết quả giống hệt nhau trong cả hai công cụ Clang 3.2 dev, G ++ 4.6 và 4.7.

R. Martinho Fernandes lưu ý rằng việc thay đổi a 's gõ vào đoạn cuối cùng để const char a[] làm cho năng suất đang const char * hai lần.

+1

Tại sao '// fine; "afas" là const char * '? Không phải vậy! http://ideone.com/4KewDe –

+0

@ R.MartinhoFernandes, cố định. – Griwes

+2

Tôi đã quản lý để giảm thêm vấn đề [ở đây] (http://liveworkspace.org/code/72b3963b4f0c2d00592b4ce00f08fc82). Rõ ràng là sự vô hướng đang gây ra vấn đề và variadic không có gì để làm với điều này. Tuy nhiên vẫn chưa tìm thấy một lời giải thích có khả năng ... Nó chắc chắn trông giống như một lỗi trình biên dịch với tôi. –

Trả lời

5

Tôi nghĩ tôi có thể trả lời phần thứ hai: Cách khắc phục? Tôi không chắc chắn nếu tôi có câu trả lời đúng bởi vì trường hợp đi qua một chuỗi sản xuất chữ, theo ý kiến ​​của tôi, vẫn là kết quả sai. Ý tưởng cơ bản để sửa chữa là sử dụng chuyển tiếp hoàn hảo hơn là hy vọng rằng loại chính xác được suy ra cho T const&. Tại sao sử dụng T const& với một mảng khiến mảng bị phân rã, mặc dù vậy tôi vẫn chưa hiểu rõ.

Sử dụng chuyển tiếp hoàn hảo, tất nhiên, có nghĩa là chức năng thực hiện nó là một kết hợp hoàn hảo và một số chuyên môn thực sự thực hiện một số chuyển đổi, ít nhất là thêm const. Vì vậy, nó là cần thiết để sử dụng một tên khác nhau. Tổng cộng, điều này có dạng như sau:

#include <iostream> 
#include <utility> 

void foo() 
{ 
} 

template<unsigned N> 
void special(const char (&)[N]) 
{ 
    std::cout << "char(&)[" << N << "]" << '\n'; 
} 

void special(const char *) 
{ 
    std::cout << "const char *" << '\n'; 
} 

template<typename T> 
void special(const T &) 
{ 
    std::cout << "Single" << '\n'; 
} 

template<typename First, typename... T> 
void foo(First&& first, T&&... rest) 
{ 
    std::cout << "Generic + " << sizeof...(T) << '\n'; 
    special(std::forward<First>(first)); 
    foo(std::forward<T>(rest)...); 
} 

int main() 
{ 
    char const* c("foo"); 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo('f', "afas", a, c, 1); 
    foo(a); 
} 
Các vấn đề liên quan