2014-12-11 16 views
6

Próbuję przeciążać operator T() użyciu SFINAE aby powrócić kopię gdy T jest podstawowym typem i const odniesienia podczas T jest klasa.umożliwić operatorowi konwersji przy użyciu SFINAE

Podczas korzystania z double w moim przykładzie poniżej, nie mogę uzyskać 2. Przeciążenie (z std::is_class) do usunięcia.

Oznacza to, że błąd dostaję to:

error: no type named ‘type’ in ‘struct std::enable_if<false, const double&>’ 
operator typename std::enable_if< std::is_class<T>::value, const T&>::type() const 
^ 

Co robię źle?

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct Foo 
{ 
    operator typename std::enable_if<!std::is_class<T>::value, T >::type() const 
    { 
     return _val; 
    } 

    operator typename std::enable_if< std::is_class<T>::value, const T&>::type() const 
    { 
     return _val; 
    } 

    T _val; 
}; 

int main() 
{ 
    Foo<double> f1; 
    f1._val = 0.3; 

    double d = f1; 
    std::cout << d << std::endl; 
    return 0; 
} 

Odpowiedz

9

T jest już znany w momencie twoje funkcje składowe klasy są instancja, więc nie występuje substytucja, a zamiast SFINAE, masz twardą błąd. Najłatwiejszym rozwiązaniem jest wprowadzenie fałszywego parametru szablonu dla operatorów przeciążających i ustawienie domyślne na T, aby możliwe było nadal odliczanie typu.

template<typename U = T> 
operator typename std::enable_if<!std::is_class<U>::value, U >::type() const 
{ 
    return _val; 
} 

template<typename U = T> 
operator typename std::enable_if< std::is_class<U>::value, const U&>::type() const 
{ 
    return _val; 
} 

Live demo

+0

Aby uzyskać nieco inny przykład i dodatkowe szczegóły, zobacz http://stackoverflow.com/questions/18100297/how-can-i-use-stdenable-if-in-a-conversion-operator – Asher

+0

@Asher Używanie SFINAE w ustawieniach domyślnych Argument szablonu działa w pytaniu, z którym łączyłeś się, ale w powyższym pytaniu, gdzie OP próbuje użyć go do zdefiniowania dwóch wzajemnie wykluczających się przeciążeń, nie będzie [jak wyjaśniono tutaj] (http://stackoverflow.com/a/29502338/241631). – Praetorian

-2

powinien przeczytać definicję std :: enable_if

szablon < bool B, klasa T = void> struct enable_if;

"Jeśli B jest prawdziwe, std :: enable_if ma typ typed publicznego public, równy T, w przeciwnym razie nie ma członka typedef."

+2

'enable_if' jest przeznaczony do SFINAE (patrz [Przykłady] (http://en.cppreference.com/w/cpp/types/enable_if) tak tu problemem jest to, że nie typedef nie jest tutaj, ale SFINAE nie działa zgodnie z oczekiwaniami. – Johan

+0

@Johan, co masz na myśli mówiąc "SFINAE nie działa zgodnie z oczekiwaniami?" Doskonale sprawdza definicję drugiego operatora (ze względu na "const T &"), pierwsze parametry szablonu z enable_if w tej chwili jest "false", nie masz zdefiniowanego 'type', koniec historii –

+2

Zobacz tę [odpowiedź] (http://stackoverflow.com/a/27433342/2439734). – Johan

3

Nie rozwiązując problemu, dlaczego niepoprawny operator nie został odrzucony, aby rozwiązać konkretny problem pod ręką, tj. , aby zwrócić go przez const ref dla typów klas lub według wartości dla innych, można znaleźć rozwiązanie przy użyciu std::conditional.

template< bool B, class T, class F > 
struct conditional; 

Zapewnia człon typu typedef, który jest zdefiniowany jako T, jeżeli B jest prawdziwe w czasie kompilacji , lub F, jeżeli B jest fałszywe.

przykład robocza:

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct Foo 
{ 
    operator typename std::conditional< 
     std::is_class<T>::value, const T&, T>::type() const 
    { 
     return _val; 
    } 

    T _val; 
}; 

int main() 
{ 
    Foo<double> f1; 
    f1._val = 0.3; 

    double d = f1; 
    std::cout << d << std::endl; 
    return 0; 
} 
+1

To wydaje się być dobrym sposobem na uniknięcie potrzeby odpowiedzi na twoje pytanie, ale warto zauważyć, że nie można go uogólnić do pracy, gdy ciała twojego operatora nie są 100 % identyczne. – hvd

+0

@hvd Zgadzam się. Jednak w tym konkretnym przypadku, gdzie wszystko, co chcę zrobić, to zwracanie przez const ref dla typów klas i wartości dla innych typów, myślę, że używanie 'std :: conditional' jest prostszym/krótszym podejściem niż posiadanie 2' std_enable_if' przeciąża. Zgodziłbyś się? –

+1

Tak, jeśli ciała dwóch operatorów są identyczne, zdecydowanie skorzystam z rozwiązania 'std :: conditional'. – Praetorian