2010-10-29 27 views
20

Đoạn mã dưới đây không thể vượt qua quá trình biên dịch, việc xem xét lỗi biên dịch này là gì?Tại sao đối số mặc định không thể được chỉ định cho một chuyên môn mẫu rõ ràng?

template<class T> void f(T t) {}; 

template<> void f<char>(char c = 'a') {} 

Thông báo lỗi: đối số mặc định không được phép trên một chuyên môn hóa rõ ràng của một hàm mẫu

+0

Nhận xét nhỏ: bạn không cần dấu chấm phẩy sau khi định nghĩa hàm. – vitaut

+1

Không thực sự trả lời câu hỏi, nhưng nó sẽ không được sạch hơn/dễ dàng hơn để sử dụng quá tải thay vì chuyên môn? Đối với một cuộc thảo luận về quá tải và chuyên môn hóa, xem các bài viết này từ Herb Sutter: [Bài báo của người dùng C/C++] (http://www.gotw.ca/publications/mill17.htm) và [GotW # 49] (http://www.gotw.ca/gotw/049.htm). –

+0

+1 đến @Luc. Nếu bạn chỉ làm 'void f (char c = 'a') {}' nó biên dịch hoàn toàn tốt. –

Trả lời

21

Tôi nghĩ rằng lý do đằng sau lỗi này là do thực tế rằng các đối số mặc định trong hàm mẫu áp dụng cho chuyên môn của nó là tốt và bạn không được phép xác định đối số mặc định nhiều hơn một lần trong C++.

xem xét như sau:

#include <iostream> 

template<class T> void f(T t = 'a') {} 

template<> void f<char>(char c) 
{ 
    std::cout << c << std::endl; 
} 

int main(int argc, char **argv) 
{ 
    f<char>(); 
} 

này sẽ in a nghĩa là chuyên môn hoá được gọi với đối số mặc định xác định trong mẫu chính.

Nếu bạn cần một đối số mặc định khác nhau cho từng chuyên ngành bạn có thể sử dụng phương pháp này minh họa dưới đây:

#include <iostream> 

template<class T> 
struct default_arg 
{ 
    static T get() { return T(); } 
}; 

template<class T> void f(T t = default_arg<T>::get()) {} 

template<> 
struct default_arg<char> 
{ 
    static char get() { return 'a'; } 
}; 

template<> void f<char>(char c) 
{ 
    std::cout << c << std::endl; 
} 

int main(int argc, char **argv) 
{ 
    f<char>(); 
} 
+0

Điều này không phải là rất tốt đẹp .. Điều này nói rằng, tất cả các loại 'T' phải có khả năng được khởi tạo với char .. Hoặc để có một toán tử cast thích hợp để char. –

+0

@Kiril Kirov: Đây chỉ là một ví dụ minh họa điểm (tại sao trình biên dịch đưa ra lỗi này). – vitaut

+0

Đúng, nhưng vẫn .. Dù sao: +1 - cho ý tưởng, được thêm vào sau khi chỉnh sửa (: –

14

C++ 98 §12.7/21 "đối số chức năng mặc định sẽ không được quy định tại các ... chuyên môn hóa rõ ràng của một mẫu hàm "#:.

Về cơ sở lý luận, tôi nghĩ rằng việc phải thực hiện với cuộc gọi luôn được giải quyết dựa trên mẫu chính. Một cuộc gọi bỏ qua một đối số được yêu cầu bởi mẫu chính, không thể được giải quyết mà không thay đổi quy tắc tra cứu.

+0

+1 để trích dẫn phần có liên quan của tiêu chuẩn. Không bao giờ giỏi về nó =) – vitaut

+1

Thật vậy, không tìm thấy chuyên môn rõ ràng bằng tra cứu tên. Khấu trừ đối số mẫu được thực hiện trên mẫu hàm, và nếu nó chỉ được gọi bởi 'f()', nó không thể suy ra 'T'. Làm thế nào nó sẽ được cho là chọn 'char'.Người ta có thể tranh luận người ta có thể làm 'f ()' và nếu một chuyên môn rõ ràng cho 'f ' tồn tại cung cấp một đối số mặc định, nó sẽ được sử dụng. Nhưng tôi thấy ít sử dụng cho điều đó và nó sẽ chỉ phức tạp hơn nữa việc khấu trừ đối số mẫu. –

2

Việc chọn trường hợp mẫu cụ thể để sử dụng dựa trên loại thông số được cung cấp. Vì vậy, việc lựa chọn chuyên môn rõ ràng được thực hiện bởi việc cung cấp một đối số char - nó chỉ là tại thời điểm đó các đối số mặc định (như bạn đã được mã hóa) sẽ đi vào chơi (nơi nó là dư thừa).

Chỉ có ý nghĩa khi cung cấp các đối số mặc định trên bản khai báo mẫu. Điểm bất lợi là bạn phải tự xác định chuyên môn thích hợp (loại bỏ một số ưu điểm trong việc sử dụng đối số mặc định ở vị trí đầu tiên).

Để đạt được hành vi mà (tôi tin) bạn muốn, hãy sử dụng như sau.

template<class T> void f(T t) {} 

template<> void f<char>(char c) {} 

void f() { f('a'); } 
Các vấn đề liên quan