2013-09-03 95 views
10

Khi tôi biên dịch đoạn mã sau, tôi nhận được một lỗi biên dịch với kêu vang, nhưng không phải với g ++/MSVC:lỗi Strange với một nhà điều hành templated quá tải

#include <string> 

template<typename T> struct Const { 
    explicit Const(T val) : value(val) {} 
    T value; 
}; 

template<typename T> struct Var { 
    explicit Var(const std::string &n) : name(n) {} 

    std::string name; 
}; 

template<typename L, typename R> struct Greater { 
    Greater(L lhs, R rhs) : left(lhs), right(rhs) {} 

    L left; 
    R right; 
}; 

template<typename L> 
Greater<L, Const<int> > operator > (L lhs, int rhs) { 
    return Greater<L, Const<int> >(lhs, Const<int>(rhs)); 
} 

template<typename R> 
Greater<Const<int>, R> operator > (int lhs, R rhs) { 
    return Greater<Const<int>, R>(Const<int>(lhs), rhs); 
} 

Var<double> d("d"); 

int main() { 
    d > 10; 
    return 0; 
} 

Các lỗi thông báo như sau:

error: overloaded 'operator>' must have at least one parameter of 
     class or enumeration type 
Greater<Const<int>, R> operator > (int lhs, R rhs) { 
        ^
./val.h:31:24: note: in instantiation of function template specialization 
     'operator><int>' requested here 
Greater<Const<int>, R> operator > (int lhs, R rhs) { 
        ^
1 error generated. 

là về chức năng điều hành không được sử dụng. Nếu, thay vào đó, tôi viết 10> d thay vì d> 10, sau đó tôi nhận được cùng một lỗi về hàm operator> khác. Phần trên biên soạn tốt theo gcc 4.4.6 và VS2012. Lỗi của tôi là gì ?

Cảm ơn bạn.

+0

Nó cũng biên dịch tốt với gcc 4.8.1: http://ideone.com/wG4Yzv (chế độ C++ 98) và http://ideone.com/8fwOWq (chế độ C++ 11). Phiên bản của bạn là gì? –

+0

@gx_ Chỉ cần thử 3.1 và 3.2, cả hai đều có vấn đề. – BoBTFish

+0

@BoBTFish Cảm ơn (quá xấu không có "Clang trực tuyến" (nữa)). Tôi tự hỏi về ví dụ rất đơn giản http://ideone.com/0Aooxo?_Edit: _ oh chờ đợi, có clang 3.0 tại http://gcc.godbolt.org/ :) và ví dụ đơn giản của tôi gây ra lỗi tương tự. _Edit (2): Cảm ơn một lần nữa. Dường như một lỗi trình biên dịch ..._ –

Trả lời

7

Clang là đúng: toán tử quá tải yêu cầu ít nhất một lớp hoặc tham số kiểu enum, nếu không chương trình bị hỏng (13,5/1). Để xem tại sao lỗi này xuất hiện, chúng tôi phải phân tích cú pháp một số pháp lý chuẩn khác.

Hãy nhớ lại Trinity Trinity của Tra cứu tên, Khấu trừ đối số và Phân giải quá tải. Bước đầu tiên tìm thấy hai quá tải operator>. Bước thứ hai suy ra các đối số mẫu cho mỗi phiên bản. Bạn có thể nghĩ rằng sự quá tải thứ hai sẽ trở thành nạn nhân của quy tắc SFINAE (14.8.2), do đó chỉ có người đầu tiên sống sót đến bước thứ ba. Tuy nhiên, không có sự cố thất bại (ví dụ như một typedef lồng nhau bị thiếu), nhưng một cấu trúc bất hợp pháp (xem trước đó đã đề cập 13.5/1). Điều đó tự làm cho chương trình không được hình thành (14.3/6)

6 Nếu việc sử dụng đối số mẫu làm phát sinh cấu trúc không đúng định dạng trong quá trình thực hiện chuyên môn mẫu, chương trình bị hỏng .

Trong 14.8.3, đề cập đến việc kiểm tra này đối với các đối số được suy luận xảy ra trước khi quá tải, vì vậy toán tử ưa thích của bạn không có cơ hội được chọn.

Với tư cách là C++ 03, bạn có thể xác định hai người bạn không phải là mẫu operator> bên trong mẫu lớp học Var<T> của mình. Chúng sẽ được tiêm vào vùng tên xung quanh (toàn cầu, trong ví dụ này) như các hàm không có khuôn mẫu với một tham số kiểu lớp, do đó lỗi trên không nên xảy ra.

+0

+1 Tôi nghĩ bạn đã đúng. – Walter

+0

Câu hỏi của OP sử dụng 'toán tử>' làm ví dụ nhưng câu trả lời của bạn nói về 'toán tử <', đây có phải chỉ là lỗi đánh máy không? – greatwolf

+0

@greatwolf tnx, được cập nhật – TemplateRex

0

Tôi phải thừa nhận, tôi không thực sự biết tại sao tiếng kêu kêu vang ở đây, nó trông giống như một lỗi (của trình biên dịch). Btw, clang 3.3 cũng thể hiện vấn đề.

Bạn có thể tắt nó bằng cách sử SFINAE:

template<typename L> 
typename std::enable_if<std::is_class<L>::value || std::is_enum<L>::value, 
         Greater<L, Const<int>>>::type 
operator > (L lhs, int rhs) { 
    return Greater<L, Const<int> >(lhs, Const<int>(rhs)); 
} 

template<typename R> 
typename std::enable_if<std::is_class<R>::value || std::is_enum<R>::value, 
         Greater<Const<int>,R>>::type 
operator > (int lhs, R rhs) { 
    return Greater<Const<int>, R>(Const<int>(lhs), rhs); 
} 
+0

Thật không may, tôi chỉ có thể sử dụng C++ 03. Đúng nếu tôi sai, nhưng std :: enable_if, std :: is_class vv là C++ 11 cấu trúc vì vậy tôi không thể sử dụng chúng – John

+0

@John enable_if là một vài dòng mã mà bạn có thể tự viết, nhưng is_class yêu cầu hỗ trợ trình biên dịch , vì vậy bạn không thể sử dụng điều này nếu không có C++ 11 – TemplateRex

0

này trông giống như một lỗi trong g ++ và VS với tôi. Trong ví dụ của bạn, loại của bạn Rint (vì toán hạng bên phải là int). Điều này sau đó làm cho chữ ký của hàm Greater<Const<int>, R> operator > (int lhs, int rhs)có cùng chữ ký (tham số) như được gắn sẵn operator< cho ints. Lưu ý rằng nó phải xem xét cả hai mẫu (và cố gắng suy ra các loại riêng biệt cho mỗi) khi quyết định sử dụng operator>: Nó không thể chỉ nhìn vào một trong số chúng và quyết định bỏ qua một mẫu khác.

+0

Khi xem xét cả hai mẫu, một bản mẫu tức thời không hợp lệ sẽ bị bỏ qua hoặc có phải là lỗi không? – John

+0

@ John không, chỉ có các lỗi thay thế không phải là lỗi (sfinae), bất kỳ cấu trúc bất hợp pháp nào khác trong quá trình khấu trừ đối số là các lỗi cứng. Xem câu trả lời của tôi để biết thêm chi tiết. – TemplateRex