2011-12-15 50 views
7

Đây là mã của tôi để kiểm tra xem lớp có hàm thành viên begin hay không:Templates instantiation nhầm lẫn

template<typename T> struct has_begin 
{ 
    struct dummy {typedef void const_iterator;}; 
    typedef typename std::conditional< has_iterator<T>::yes, T, dummy>::type TType; 
    typedef typename TType::const_iterator Iter; 
    struct fallBack{ Iter begin() const ; Iter end() const;}; 
    struct checker : T, fallBack {}; 
    template <typename B, B> struct cht; 
    template<typename C> static char check(cht< Iter (fallBack::*)() const, &C::begin>*); // problem is here 
    template<typename C> static char (&check(...))[2]; 
public: 
    enum {no = (sizeof(check<checker>(0))==sizeof(char)), 
    yes=!no}; 
}; 

Nếu tôi thay đổi số thứ hai của cht trong check(cht< Iter (fallBack::*)() const, &C::begin>*); để &checker::begin, này không làm thay đổi ngữ nghĩa của mã kể từ khi mẫu đối số thứ hai cht 's luôn là checker do này enum {no = (sizeof(check<checker>(0))==sizeof(char))

nhưng thay đổi mã kết quả trong error nay đó là:

prog.cpp: In instantiation of 'has_begin<std::vector<int> >': 
prog.cpp:31:51: instantiated from here 
prog.cpp:23:38: error: reference to 'has_begin<std::vector<int> >::checker::begin' is ambiguous 

Tôi muốn biết lý do đằng sau hành vi này là gì.

+0

Cấu trúc của bạn rất phức tạp. Nó phải làm gì? Có vẻ như một kiểm tra nếu lớp T có một hàm thành viên có tên là bắt đầu –

+0

@VJovic Bạn nói đúng, tôi đã chỉnh sửa dòng đầu tiên của câu hỏi :) –

+0

Lỗi nào bạn nhận được nếu bạn thực hiện thay đổi? –

Trả lời

3

từ bài viết trên Wikipedia về SFINAE - Thay Failure không phải là một Lỗi:

[...] when creating a candidate set for overload resolution, some (or all) candidates of that set may be the result of substituting deduced template arguments for the template parameters. If an error occurs during substitution, the compiler removes the potential overload from the candidate set instead of stopping with a compilation error [...]

Trong code của bạn như được đăng, một lỗi mơ hồ xảy ra trong khi instantiating chức năng template check với tham số C == typename has_begin<T>::checker, và rằng sự thay thế dẫn đến lỗi, do đó việc tạo ra sự đơn giản hóa từ bộ quá tải.

Nếu bạn thay đổi mã của mình, lỗi ambiguaty tương tự sẽ xảy ra với &checker::begin. Lần này, tuy nhiên, nó không phải là kết quả của việc thay thế tham số mẫu C cho mẫu chức năng check. Việc cho phép tham số mẫu T của struct has_begin không liên quan đến quy tắc SFINAE, vì mẫu đó đã được khởi tạo thành công.

+0

đoạn đầu tiên của bạn không có ý nghĩa với tôi. bạn giải thích lý do rõ ràng hơn? –

+0

@FreakEnum đã chỉnh sửa câu trả lời, hy vọng điều đó sẽ giúp – wolfgang