2012-12-20 17 views
23

Dlaczego to nie kompiluje się z gcc48 i clang32? BłądDlaczego warto skompilować błąd za pomocą enable_if

#include <type_traits> 

template <int N> 
struct S { 

    template<class T> 
    typename std::enable_if<N==1, int>::type 
    f(T t) {return 1;}; 

    template<class T> 
    typename std::enable_if<N!=1, int>::type 
    f(T t) {return 2;}; 
}; 

int main() { 
    S<1> s1; 
    return s1.f(99); 
} 

GCC: error

/home/lvv/p/sto/test/t.cc:12:2: error: no type named ‘type’ in ‘struct enable_if<false, int>’ 
    f(T t) {return 2;}; 
^

dzyń:

/home/lvv/p/sto/test/t.cc:11:26: error: no type named 'type' in 'std::enable_if<false, int>'; 'enable_if' cannot be used to 
     disable this declaration 
     typename std::enable_if<N!=1, int>::type 
           ^~~~ 
/home/lvv/p/sto/test/t.cc:16:7: note: in instantiation of template class 'S<1>' requested here 
     S<1> s1; 
      ^

EDIT - ROZWIĄZANIE

Mam akceptowane odpowiedź od Karola Salvia, ale ze względów praktycznych ja nie był w stanie zastosować proponowanego obejścia (specjalizacja na N). Znalazłem inne obejście, które działa dla mnie. Dokonaj enable_if zależą T:

typename std::enable_if<(sizeof(T),N==1), int>::type 
+1

Czy jesteś pewien, że to będzie działać tak czy inaczej? Nie można przeciążać metod po prostu przez ich typ zwracany (chyba że 'enable_if' jest zaimplementowany jako konstrukcja językowa, a nie przez, jak się obecnie domyślam, prosta klasa szablonów). – zneak

+0

Dlaczego obejście problemu polegające na tym, że włączenie opcji enable_if zależy dokładnie od T, dokładnie? –

+0

Rozwiązanie nie działa dla mnie! Dostałem 'error: no matching function for call ...' –

Odpowiedz

14

Ponieważ używasz enable_if bez użycia parametru szablonu T w szablonach funkcyjnych. Jeśli chcesz specjalizować się, gdy struct S ma określoną wartość parametru szablonu N, musisz użyć specjalizacji szablonów klas.

template <int N, class Enable = void> 
struct S { }; 

template <int N> 
struct S<N, typename std::enable_if<N == 1>::type> 
{ 
    .... 
}; 
5

Aby uzyskać std::enable_if pracować tak, jesteś powołując się na SFINAE. Niestety, w momencie, w którym deklarują

S<1> s1; 

będzie instancję wszystkich deklaracji członkowskich S<1> „s. SFINAE wejdzie w grę tylko w tym momencie, jeśli S<1> jest źle sformułowanym konstruktem. Nie jest. Niestety, zawiera on funkcję, która jest nieważna, dlatego instancja S<> jest nieprawidłowa.

na takie rzeczy jak to, że mogę odłożyć do oddzielnego szablonu struct:

template <bool B> 
struct f_functor { 
    template <typename T> 
    static int f(T t) { return 1; } 
}; 

template <> 
struct f_functor<false> { 
    template <typename T> 
    static int f(T t) { return 2; } 
}; 

template <int N> 
struct S { 

    template<class T> 
    typename int f(T t) { return f_functor<N==1>::f(t); } 
}; 
+1

[To pytanie] (http: // stackoverflow.com/questions/6972368/stdenable-if-to-condition-compile-a-member-function) ma więcej informacji. – Anthony

1

W tym przypadku można myśleć o wcale nie używając enable_if. Jest posible prostu specjalizują f:

template <int N> 
struct S { 
    template<class T> int f(T t); 
}; 

template<int N> 
template<class T> 
int S<N>::f(T t) { return 2; } 

template<> 
template<class T> 
int S<1>::f(T t) { return 1; } 

int main() { 
    S<1> s1; 
    return s1.f(99); 
} 
6

Użyj parametru szablonu domyślnego logiczną, na przykład:

template <int N> 
struct S { 

    template<class T, bool EnableBool=true> 
    typename std::enable_if<N==1 && EnableBool, int>::type 
    f(T t) {return 1;}; 

    template<class T, bool EnableBool=true> 
    typename std::enable_if<N!=1 && EnableBool, int>::type 
    f(T t) {return 2;}; 
}; 
7

Cóż, nie jestem pewien, co chcesz zrobić, ale może ten kod pomoże :

#include <iostream> 

template <int N> 
struct S { 

    template<class T=int> 
    typename std::enable_if<N==1, T>::type 
    f(T t) {return 1;} 

    template<class T=int> 
    typename std::enable_if<N!=1, T>::type 
    f(T t) {return 2;} 
}; 

int main() 
{ 
    S<1> s1; 
    S<2> s2; 
    std::cout << s1.f(99) << " " << std::endl << s2.f(5); 
} 

drukuje 1 i 2.