2013-07-24 13 views
35

Rozważmy następujący kod:Wybierz Konstruktor klasy używając 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; 
} 

Chcę selektywnie zdefiniować konstruktora :: A (int) tylko dla niektórych typów korzystając enable_if. Dla wszystkich innych typów istnieje domyślny konstruktor A :: A (...), który powinien być domyślnym przypadkiem dla kompilatora, gdy podstawianie się nie powiedzie. Jednak ma to sens dla mnie kompilator gcc w wersji 4.9.0 (20130714) jest nadal narzeka

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) {};

Czy coś jak to możliwe dla konstruktora? Czy jest to możliwe z innymi konstruktorami (copy-constructor i move-constructor)?

+0

Czy może to być klasa fabryka pomocników? –

Odpowiedz

31

Myślę, że to nie działa z pojedynczym domyślnym parametrem szablonu, ponieważ jego wartość musi zostać rozwiązana po utworzeniu instancji klasy.

Musimy odroczyć podstawienie do punktu tworzenia szablonu konstruktora. Jednym ze sposobów jest ustawienie domyślnego parametru szablonu na T i dodanie do konstruktora dodatkowego atrapa:

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

lepsze wyjaśnienie niż moje: D –

+0

@JoelFalcou Twój naprawdę działa. [Ten jeszcze nie jest] (http://coliru.stacked-crooked.com/view?id=15f3b29d734e0b4f765cf6fddc19896d-fcf98f666e0b68774061981371328429) – Rapptz

+0

@Rapptz Mój zły, ponieważ jest używany w domyślnym parametrze szablonu. Musi być w podpisie konstruktora. Naprawię to. – jrok

8

Zwykle odbywa się to za pomocą anonimowego defaulted argumentu:

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

Nie można używać parametrów szablonu z klasy do SFINAE z metod. więc jeden ze sposobów jest dodanie rodzaj manekina zastępując int:

patrz: 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; 
} 

To działa, ponieważ użyć parametru szablonu member aby SFINAE się konstruktora, ale test jest zawsze prawdziwe, więc nie robi Zanieczyszcza twoje kontrole

+3

To nadal daje ten sam błąd i byłem pod wrażeniem, że metoda OP była najczęstsza. – chris

+0

@chris Tak naprawdę jest. – Rapptz

+0

Jest w C++ 11. Właśnie zauważyłem std :: enable_if. –

Powiązane problemy