2012-10-26 7 views
8

Biorąc pod uwagę deklarację klasyCzy można użyć std :: enable_if, aby wybrać specjalizację szablonów członków?

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

Chciałbym specjalizować A::foo różnych rodzajów (int, ...) i zajęcia typu (POD, non-POD) z T. Niestety, nie wydaje mi się, aby użyć tego ostatniego. Dodaje się nie kompiluje:

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! 

Problem jest prawdopodobnie ze względu na std::enable_if<...> rzeczy będącej częścią podpisu funkcji, a ja nie ogłoszono takiego członka wewnątrz A. Jak więc mogę wyspecjalizować członka szablonu na podstawie cech typu?

Odpowiedz

4

widzę żadnego powodu specjalizacji tutaj, przeciążenia funkcja wydaje się wystarczające w moim umyśle.

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

Podczas sprawdzania POD POD lub nie, trzeba tylko te dwie możliwości, a więc funkcja bardziej ogólny i nie jest konieczna (i niedozwolone, ponieważ byłoby niejednoznaczne). Potrzebujesz więcej? Możesz sprawdzić typy jawne bez specjalizacji z pomocą std::enable_if<std::is_same<int, T>::value, T>::type.

+0

Ale nie można przeciążać tylko na typie zwrotnym ... –

+0

@Janiel Gehriger 'enable_if' został stworzony do warunkowego usuwania funkcji z przeciążeniowych rozdzielczości, więc prawie dokładnie w tym przypadku. – nijansen

+0

Tak, ale nadal mam 'A :: foo ()' (i wiele innych specjalizacji dla niektórych określonych typów), które będą kolidować z tym, co zostało wybrane przez 'enable_if'. –

4

Wolałbym do przodu to do struktury, która ma obsługiwać to dobrze:

#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

Użycie 'std :: enable_if' jest tu nieco okrężne. Jeśli szablon podstawowy przyjmuje parametr "typename = std :: true_type" jako parametr domyślny, to np. 'typename std :: is_pod :: type' to krótszy sposób na osiągnięcie tej samej częściowej specjalizacji. –

+0

Nieźle - ale muszę uzyskać dostęp do danych członka z FooCaller, więc musiałbym ponownie przekazać połączenie do funkcji członka A. To zaczyna wyglądać bardzo skomplikowanie. –

+0

Cóż, po prostu użyj prostego 'szablonu używając not_ = std :: integral_constant ;'. Lub uczynić go 'struct' dla kompilatorów, które nie obsługują jeszcze przy użyciu aliasów:' template struct not_: std :: integral_constant {}; 'i użyj tego w częściowym spec:' FooCaller > :: type> ' – Xeo