2012-11-12 6 views
5

tôi cố gắng chuyên mẫu nếu một lớp có một chức năng đặc biệt thành viên như thế này (tìm thấy ở đây trong ví dụ khác):mẫu để kiểm tra sự tồn tại của chức năng thành viên quá tải

template <typename T> 
class has_begin 
{ 
    typedef char one; 
    typedef long two; 

    template <typename C> static one test(decltype(&C::AnyFunc)) ; 
    template <typename C> static two test(...); 

public: 
    enum { value = sizeof(test<T>(0)) == sizeof(char) }; 
    enum { Yes = sizeof(has_begin<T>::test<T>(0)) == 1 }; 
    enum { No = !Yes }; 
}; 

này hoạt động tốt cho đến khi AnyFunc bị quá tải :

class B : public vector<int> 
{ 
public: 
    void AnyFunc() const; 
    void AnyFunc(); 
}; 

Tôi làm cách nào để viết lại mã thử nghiệm của mình để nhận mẫu "Có" từ mẫu của tôi?

+0

Câu hỏi hay. Một vấn đề rất tầm thường mà có thể đi lặng lẽ không bị phát hiện do SFINAE. – iammilind

Trả lời

1

Tìm thấy phiên bản mà hoạt động:

template <typename C> static one test(decltype(((C*)0)->AnyFunc())*) ; 

Nếu bạn muốn xác minh rằng đối tượng có chức năng const, sử dụng này:

template <typename C> static one test(decltype(((const C*)0)->AnyFunc())*) ; 

phiên bản này sẽ không phát hiện hàm với đối số:

class B : public std::vector<int> 
{ 
public: 
    //void AnyFunc() const; 
    //void AnyFunc(); 
    int AnyFunc(int); 
}; 
+1

@Klaus Đó là lý do tại sao tôi đã thêm '*' sau 'decltype()' ... Tôi đã kiểm tra xem nó có hoạt động trước khi đăng bài hay không: http://ideone.com/8Tli7t – PiotrNycz

+0

Sau khi đọc câu trả lời thứ hai, tôi đã có giải pháp của bạn để chạy trong môi trường của tôi. Cảm ơn rất nhiều! – Klaus

+0

Vâng, tôi quên * sau khi decltype! Xin lỗi vì lỗi của tôi! Tôi nhận được điều này để làm việc sau khi nhìn phía sau std :: add_pointer từ câu trả lời thứ hai. – Klaus

2

Việc sử dụng tên hàm bị quá tải không có đối số (13.4p1) phải được giải quyết để hát le overload (13.4p4), nếu không thì sẽ xảy ra lỗi thay thế.

Nếu bạn đang thử nghiệm cho sự tồn tại của một hàm thành viên thì bạn nên biết các đối số bạn có kế hoạch để gọi nó với:

template <typename C> static one test(
     typename std::add_pointer<decltype(std::declval<C>().AnyFunc())>::type); 

Nói chung, bạn có thể sử dụng một mẫu variadic và một mô hình tương tự như result_of :

template <typename C, typename... Args> static one test(
     typename std::add_pointer<decltype(
      std::declval<C>(std::declval<Args>()...).AnyFunc())>::type); 

Sử dụng add_pointer phép này để làm việc với các loại chức năng trả lại mà không phải thừa nhận là loại chức năng lập luận (ví dụ void).