2013-07-24 45 views
35

Hãy xem xét đoạn mã sau:Chọn lớp constructor sử dụng enable_if

#include <iostream> 
#include <type_traits> 

template <typename T> 
struct A { 
    int val = 0; 

    template <class = typename std::enable_if<T::value>::type> 
    A(int n) : val(n) {}; 
    A(...) { } 

    /* ... */ 
}; 

struct YES { constexpr static bool value = true; }; 
struct NO { constexpr static bool value = false; }; 

int main() { 
    A<YES> y(10); 
    A<NO> n; 
    std::cout << "YES: " << y.val << std::endl 
       << "NO: " << n.val << std::endl; 
} 

tôi muốn chọn lọc xác định constructor A :: A (int) chỉ dành cho một số loại sử dụng enable_if. Đối với tất cả các kiểu khác, hàm tạo mặc định A :: A (...) cần phải là trường hợp mặc định cho trình biên dịch khi không thể thay thế được. Tuy nhiên, điều này có ý nghĩa đối với trình biên dịch của tôi (phiên bản gcc 4.9.0 20130714) vẫn đang khiếu nại

sfinae.cpp: In instantiation of 'struct A': sfinae.cpp:19:11:
required from here sfinae.cpp:9:5: error: no type named 'type' in
'struct std::enable_if'
A(int n) : val(n) {};

Có phải cái này có thể cho người xây dựng không? Điều này có thể xảy ra với một hàm tạo khác (copy-constructor và move-constructor) không?

+0

Có thể là lớp nhà máy trợ giúp kinda? –

Trả lời

31

Tôi nghĩ rằng điều này không thể làm việc với một tham số mẫu mặc định duy nhất, bởi vì giá trị của nó cần được giải quyết khi mẫu lớp được khởi tạo.

Chúng tôi cần trì hoãn thay thế cho điểm khởi tạo mẫu khởi tạo. Một cách là đặt tham số mẫu mặc định thành T và thêm thông số giả bổ sung vào hàm tạo:

template<typename U = T> 
A(int n, typename std::enable_if<U::value>::type* = 0) : val(n) { } 
+0

giải thích tốt hơn tôi: D –

+0

@ JoelFalcou Yours thực sự hoạt động. [Điều này vẫn không] (http://coliru.stacked-crooked.com/view?id=15f3b29d734e0b4f765cf6fddc19896d-fcf98f666e0b68774061981371328429) – Rapptz

+0

@Rapptz Điều xấu của tôi là vì nó được sử dụng trong tham số mẫu mặc định. Nó cần phải có chữ ký của nhà xây dựng. Tôi sẽ sửa chữa nó. – jrok

8

Thông thường điều này được thực hiện bằng một cuộc tranh cãi defaulted nặc danh:

A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {}; 

Bạn không thể sử dụng các thông số mẫu từ lớp để SFINAE ra phương pháp. SO một cách là thêm một loại hình nộm thay thế int:

see: http://ideone.com/2Gnyzj

#include <iostream> 
#include <type_traits> 

template <typename T> 
struct A { 
    int val = 0; 

    template<typename Integer 
      ,typename = typename std::enable_if<T::value && sizeof(Integer)>::type 
      > 
    A(Integer n) : val(n) {}; 

    A(...) {} 
    /* ... */ 
}; 

struct YES { constexpr static bool value = true; }; 
struct NO { constexpr static bool value = false; }; 

int main() { 
    A<YES> y(10); 
    A<NO> n; 
    std::cout << "YES: " << y.val << std::endl 
       << "NO: " << n.val << std::endl; 
} 

này hoạt động vì bạn sử dụng một tham số thành viên mẫu để SFINAE ra các nhà xây dựng nhưng các thử nghiệm là luôn luôn đúng nên nó doesn 't gây ô nhiễm séc của bạn

+3

Điều đó vẫn cho cùng một lỗi, và tôi đã ấn tượng rằng phương pháp của OP là một phương pháp phổ biến nhất. – chris

+0

@chris Nó thực sự là. – Rapptz

+0

Nó có trong C++ 11. Tôi chỉ nhận thấy std :: enable_if. –

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