2012-10-26 54 views
8

Cho một khai báo lớpCó thể sử dụng std :: enable_if để chọn chuyên môn về mẫu thành viên không?

class A { 
    template <typename T> T foo(); 
}; 

Tôi muốn chuyên A::foo với nhiều loại hình (int, ...) và các lớp học kiểu (POD, không POD) của T. Thật không may, tôi dường như không thể sử dụng std::enable_if cho mục đích sau. Sau đây không biên dịch:

template <> int A::foo<int>(); // OK 

template <typename T> 
typename std::enable_if<is_pod<T>::value, T>::type foo(); // <<<< NOT OK! 

template <typename T> 
typename std::enable_if<!is_pod<T>::value, T>::type foo(); // <<<< NOT OK! 

Vấn đề này có lẽ là do sự std::enable_if<...> thứ là một phần của chữ ký chức năng, và rằng tôi đã không công bố bất kỳ thành viên đó bên A. Vì vậy, làm thế nào tôi có thể chuyên một thành viên mẫu dựa trên các đặc điểm kiểu?

Trả lời

4

Tôi thấy không có lý do gì để chuyên đây, quá tải chức năng dường như đủ trong tâm trí tôi.

struct A 
{ 
    template <typename T> 
    typename std::enable_if<std::is_integral<T>::value, T>::type foo() 
    { 
     std::cout << "integral" << std::endl; 
     return T(); 
    } 

    template <typename T> 
    typename std::enable_if<!std::is_integral<T>::value, T>::type foo() 
    { 
     std::cout << "not integral" << std::endl; 
     return T(); 
    } 
} 

Khi kiểm tra POD hoặc không có POD, bạn chỉ có hai lựa chọn này, vì vậy chức năng chung hơn là không cần thiết (và không được phép, vì sẽ mơ hồ). Bạn cần nhiều hơn thế? Bạn có thể kiểm tra các loại rõ ràng mà không cần chuyên môn hóa với sự trợ giúp của std::enable_if<std::is_same<int, T>::value, T>::type.

+0

Nhưng bạn không thể quá tải trên kiểu trả về ... –

+0

@Daniel Gehriger 'enable_if' đã được thực hiện cho các chức năng loại bỏ có điều kiện từ độ phân giải quá tải, vì vậy khá nhiều cho trường hợp này chính xác. – nijansen

+0

Có, nhưng tôi vẫn có 'A :: foo ()' (và nhiều chuyên môn khác cho một số loại cụ thể) sẽ xung đột với bất kỳ điều gì đã được chọn bởi 'enable_if'. –

4

tôi muốn chỉ về phía trước này cho một cấu trúc, mà xử lý này cũng:

#include <type_traits> 
#include <iostream> 

template <typename T, typename = void> 
struct FooCaller; 

class A { 
public: 
    template <typename T> 
    T foo() { 
     // Forward the call to a structure, let the structure choose 
     // the specialization. 
     return FooCaller<T>::call(*this); 
    } 
}; 

// Specialize for PODs. 
template <typename T> 
struct FooCaller<T, typename std::enable_if<std::is_pod<T>::value>::type> { 
    static T call(A& self) { 
     std::cout << "pod." << std::endl; 
     return T(); 
    } 
}; 

// Specialize for non-PODs.  
template <typename T> 
struct FooCaller<T, typename std::enable_if<!std::is_pod<T>::value>::type> { 
    static T call(A& self) { 
     std::cout << "non-pod." << std::endl; 
     return T(); 
    } 
}; 

// Specialize for 'int'. 
template <> 
struct FooCaller<int> { 
    static int call(A& self) { 
     std::cout << "int." << std::endl; 
     return 0; 
    } 
}; 
+3

Sử dụng 'std :: enable_if' ở đây là một vòng xuyến nhỏ. Nếu mẫu chính thừa nhận 'typename = std :: true_type' làm thông số mặc định thì ví dụ: 'typename std :: is_pod :: type' là một cách ngắn hơn để đạt được cùng một chuyên môn hóa một phần. –

+0

Không tệ - nhưng tôi cần truy cập dữ liệu thành viên từ FooCaller, vì vậy tôi sẽ phải chuyển tiếp cuộc gọi đến chức năng thành viên của A. Điều đó bắt đầu trông rất phức tạp. –

+0

Vâng, chỉ cần có một 'mẫu đơn giản bằng cách sử dụng not_ = std :: integral_constant ;'. Hoặc làm cho nó là một 'struct' cho các trình biên dịch không hỗ trợ sử dụng bí danh:' template struct not_: std :: integral_constant {}; 'và sử dụng nó trong phần spec:' FooCaller > :: type> ' – Xeo

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