2011-01-13 29 views
12

Tôi đã gặp phải một số mã mà tôi nghĩ rằng nên biên dịch, nhưng không. Vì vậy, tôi hy vọng một số các chuyên gia tiêu chuẩn địa phương ở đây tại SO có thể giúp :-).Lỗi mẫu g ++ tiềm năng?

tôi về cơ bản có một số mã mà giống như thế này:

#include <iostream> 

template <class T = int> 
class A { 
public: 
    class U { 
    }; 

public: 
    U f() const { return U(); } 
}; 

// test either the work around or the code I want... 
#ifndef USE_FIX 
template <class T> 
bool operator==(const typename A<T>::U &x, int y) { 
    return true; 
} 
#else 
typedef A<int> AI; 
bool operator==(const AI::U &x, int y) { 
    return true; 
} 
#endif 

int main() { 
    A<int> a; 
    std::cout << (a.f() == 1) << std::endl; 
} 

Vì vậy, để mô tả những gì đang xảy ra ở đây. Tôi có một mẫu lớp (A) có lớp nội bộ (U) và ít nhất một hàm thành viên có thể trả về một thể hiện của lớp nội bộ đó (f()).

Sau đó, tôi đang cố tạo hàm operator== so sánh loại nội bộ này với một loại khác (trong trường hợp này là int, nhưng dường như không quan trọng).

Khi USE_FIXkhông định nghĩa tôi nhận được lỗi sau:

test.cc: In function 'int main()': 
test.cc:27:25: error: no match for 'operator==' in 'a.A<T>::f [with T = int]() == 1' 

Mà dường như lẻ, vì tôi là rõ ràng (tôi nghĩ) xác định một templated operator== mà nên bao gồm này, trên thực tế nếu tôi chỉ làm một chút công việc cho trình biên dịch (cho phép USE_FIX), sau đó tôi không còn nhận được một lỗi. Thật không may, "sửa lỗi" không hoạt động một cách tổng quát, chỉ cho một phiên bản cụ thể của mẫu.

Đây có phải là hoạt động như tôi mong đợi không? Hay điều này đơn giản là không được phép?

BTW: nếu vấn đề tôi đang sử dụng gcc 4.5.2.

+1

Đơn giản là không được phép. Nếu tôi biết thêm về vấn đề của bạn, tôi có thể đề xuất thiết kế lại phù hợp. –

+0

+1 cho câu hỏi hay. :-) – Nawaz

+0

có thể trùng lặp của [Làm thế nào để suy ra loại lớp từ kiểu phương thức trong các mẫu C++?] (Http://stackoverflow.com/questions/3830491/how-to-deduce-class-type-from-method-type- in-c-templates) –

Trả lời

15

Vấn đề với const typename A<T>::U &xU là loại phụ thuộc và trình biên dịch không thể suy ra T từ đối số (đây là một trong ngữ cảnh không được đặt trước).

Bạn có thể, ví dụ, có hai chuyên ngành của A:

class X { }; 
class Y { }; 
class Z { }; 

template <> class A<X> { 
public: 
    typedef Z U; 
}; 

template <> class A<Y> { 
public: 
    typedef Z U; 
}; 

Nếu bạn sau đó gọi:

Z a; 
a == 1; 

gì nên trình biên dịch suy T như? X? Y?

Một giải pháp trong trường hợp đặc biệt này là để khai báo operator== làm bạn nontemplate bên trong lớp mẫu:

template <class T = int> 
class A { 
public: 
    class U { 
    }; 

    friend bool operator==(const U& x, int y) { 
     return true; 
    } 

public: 
    U f() const { return U(); } 
}; 
+0

+1 để có câu trả lời hay cho câu hỏi hay! – Nawaz

+0

@James: nhân tiện, 'Z' nên được khai báo bên trong mẫu lớp, chỉ khi đó tình huống của anh ấy và ví dụ của bạn sẽ phù hợp với nhau. bạn nói gì? Ý tôi là, ở đây 'Z' độc lập với' A', trong khi 'U' trong câu hỏi là một kiểu phụ thuộc. – Nawaz

+3

@Nawaz: Không quan trọng liệu 'Z' có phụ thuộc hay không; điều quan trọng là 'U' phụ thuộc. 'Z' có thể là bất cứ thứ gì. (Ban đầu tôi đã sử dụng 'int', nhưng đó là sai vì mẫu chức năng thậm chí sẽ không được xem xét trong quá trình phân giải quá tải do toán tử tích hợp, vì vậy tôi đã giới thiệu' Z' như một kiểu không có quá tải nontemplate của toán tử ' == '). –

11
template <class T> 
bool operator==(const typename A<T>::U &x, int y) { 
    return true; 
} 

Sử dụng mẫu này, nó không được phép (hoặc đôi khi có thể) để suy ra thông số mẫu T từ loại x. Đó là cái được gọi là ngữ cảnh không thể suy diễn. (VD: Ai đó có thể chuyên A cho một tham số khác nhau, nói double và làm A<double>::U một typedef cho A<int>::U.)

Không có cách giải quyết, bạn sẽ phải xác định rõ ràng các thông số mẫu mà cho operator== làm cho cú pháp xấu xí.

+1

Tôi nghĩ lời giải thích này tốt hơn lời giải thích của James. Ngắn gọn và chính xác. +1 – Nawaz

4

Không được phép vì lý do khá rõ ràng. Trong trường hợp chung thực sự không có cách nào trình biên dịch có thể suy ra đối số mẫu từ cuộc gọi của bạn tới toán tử ==. Dường như bạn giả định rằng kiểu lồng nhau U định nghĩa duy nhất đặc tính kèm theo A kèm theo. Đó là không đúng, có thể được minh họa bằng ví dụ sau với hai chuyên ngành rõ ràng của A

template <> class A<int> { 
public: 
    class U {}; 
}; 

template <> class A<double> { 
public: 
    typedef A<int>::U U; 
}; 

Trong trường hợp này, nếu bạn gọi templated hành == với một đối số kiểu A<int>::U trình biên dịch không thể suy ra mẫu luận T cho nhà điều hành templated ==. Nên Tint hoặc double? Không có cách nào để nói.

Để tránh những sự mơ hồ này, các tình huống như vậy được gọi là ngữ cảnh không được suy luận. Khấu trừ các đối số mẫu lớp bao quanh từ một kiểu lồng nhau là một ví dụ về ngữ cảnh không được suy luận.

+0

+1 để có câu trả lời hay cho câu hỏi hay! – Nawaz

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