2017-05-16 14 views
40

Tôi đã lãng phí vô số giờ để xác định vấn đề với gcc. Tôi muốn kiểm tra cơ sở mã của chúng tôi với một trình biên dịch khác để tìm thêm các cảnh báo rằng Clang có thể đã bị bỏ qua. Tôi đã bị sốc rằng thực tế một nửa của dự án dừng lại để biên dịch do sự thất bại của mẫu khấu trừ đối số. Ở đây tôi đã cố gắng để câm trường hợp của tôi xuống phần đơn giản nhất của mã.Tất cả các phiên bản của cuộc đấu tranh GCC với mẫu có loại mặc định theo định nghĩa

#include <type_traits> 

struct Foo 
{ }; 

// This is a template function declaration, where second template argument declared without a default 
template <typename T, typename> 
void foo(const Foo & foo, T t); 

// This is a template function definition; second template argument now has a default declared 
template <typename T, typename = typename std::enable_if<1>::type> 
void foo(const Foo & foo, T t) 
{ 
} 

int main(int argc, char ** argv) 
{ 
    foo(Foo{}, 1); 
    return 0; 
} 

Bỏ qua một 1 trong std::enable_if<1>. Rõ ràng đó là một giá trị không đổi chỉ để không phức tạp những điều khi nó không quan trọng.

Đoạn mã biên dịch [1] với kêu vang (3.4 qua 4.0), icc (16, 17), Visual C++ (19.00.23506). Về cơ bản, tôi không thể tìm thấy bất kỳ trình biên dịch C++ 11 nào khác, ngoại trừ gcc (4.8 đến 7.1), không biên dịch đoạn mã này.

Câu hỏi đặt ra là ai đúng và ai sai ở đây? gcc có hoạt động theo tiêu chuẩn không?

Rõ ràng đây không phải là vấn đề quan trọng. Tôi có thể dễ dàng di chuyển std::enable_if đến tuyên bố. Nạn nhân duy nhất sẽ là thẩm mỹ. Nhưng nó là tốt đẹp để có thể ẩn một 100 ký tự xấu xí dài std::enable_if đoạn mã, mà không phải là ngay lập tức có liên quan cho người sử dụng chức năng thư viện, trong việc thực hiện.


Ví dụ trực tiếp trên godbolt.org.

+2

Trên en.cppreference.com nó nói cho [đối số mẫu mặc định] (http://en.cppreference.com/w/cpp/language/template_parameters#Default_template_arguments) »Đối số mẫu mặc định xuất hiện trong các khai báo và định nghĩa được hợp nhất tương tự với các đối số hàm mặc định «. Đối với [đối số hàm mặc định] (http://en.cppreference.com/w/cpp/language/default_arguments) tôi tìm thấy »... được chỉ định bằng cách sử dụng cú pháp sau cho tham số trong danh sách tham số của khai báo hàm« . Nếu tôi giải thích điều này một cách chính xác, thì bạn * có * để có đối số mặc định trong khai báo. –

+0

@HenriMenke, nó hoạt động cho các chức năng trong ** gcc **: https://godbolt.org/g/kXNbYi. Dường như ** gcc ** có tiêu chuẩn kép cho các chức năng và mẫu ... – GreenScape

+0

@HenriMenke Xem ví dụ về 'template <...> lớp A' ở mức 14.1/10. Nó hoạt động như trong g ++, nhưng không phải nếu bạn thay thế một lớp với một hàm. –

Trả lời

34

gì tiêu chuẩn nói ([1] trang 350):

Tập hợp các mẫu mặc định-đối số có sẵn để sử dụng với một tuyên bố hoặc định nghĩa mẫu thu được bằng cách sáp nhập mặc định đối số từ định nghĩa (nếu trong phạm vi) và tất cả các khai báo trong phạm vi theo cùng một cách đối số hàm mặc định là (8.3.6). [ Ví dụ:

template<class T1, class T2 = int> class A; 
template<class T1 = int, class T2> class A; 
is equivalent to 
template<class T1 = int, class T2 = int> class A; 

- end dụ]

Vì vậy, GCC là sai ở đây. Nó bỏ qua các đối số mẫu mặc định trong các khai báo.

Không phải tất cả các khai báo, chỉ có khai báo mẫu chức năng. khai báo lớp mẫu là okay:

#include <type_traits> 

template <typename T, typename> 
struct Foo; 

template <typename T, typename = typename std::enable_if<1>::type> 
struct Foo 
{ 
    T t; 
}; 

int main() 
{ 
    Foo<int> foo; 
    return 0; 
} 

sống ví dụ về godbolt.org


Có lẽ đó là do bản chất của cách lập luận không mặc định được suy luận. Trong mẫu hàm, chúng được khấu trừ từ các đối số hàm. Trong mẫu lớp, chúng ta phải xác định chúng một cách rõ ràng.

Dù sao, tôi đã tạo một bug report.

+1

Đối số mẫu mặc định cho mẫu chức năng tương đối mới (C++ 11). Không có gì đáng ngạc nhiên khi những người GCC bỏ lỡ nó. –

Các vấn đề liên quan