2013-03-24 18 views
13

Próbuję zwrócić wartość int64_t, jeśli std::is_integral<>::value jest prawdziwa.Jak użyć std :: is_integral <>, aby wybrać implementację?

W przeciwnym razie chciałbym zadzwonić pod numer to_int64t() na obiekcie.

Moja poniższa próba nie działa, ponieważ częściowa specjalizacja szablonów funkcji jest niedozwolona.

KOD

#include <type_traits> 
#include <cstdint> 

template<class T,bool is_integral_type> 
int64_t to_int64t(const T& t) 
{ 
     return t; 
} 

template<class T> 
int64_t to_int64t<T,std::is_integral<T>::value>(const T& t) 
{ 
     return t; 
} 

template<class T> 
int64_t to_int64t<T,!std::is_integral<T>::value>(const T& t) 
{ 
     return t.to_int64t(); 
} 

int main() 
{ 
     int64_t i = 64; 
     auto x = to_int64t(i); 
} 
+0

możliwym dwóch egzemplarzach: http://stackoverflow.com/questions/12073689/c11-template-function-specialization-for-integer- typeses – legends2k

Odpowiedz

28

szablony funkcja nie może być częściowo wyspecjalizowane i, w ogóle, to nie jest dobry pomysł, aby korzystać z szablonu funkcji specjalizacji.

Jednym ze sposobów osiągnięcia tego, co chcesz, jest użycie techniki zwanej tag wysyłki, który zasadniczo polega na zapewnieniu funkcji przesyłania dalej, że dobór odpowiedniego przeciążenie w oparciu o wartość dodatkową manekina argumentu:

#include <type_traits> 
#include <cstdint> 

template<class T> 
int64_t to_int64t(const T& t, std::true_type) 
{ 
    return t; 
} 

template<class T> 
int64_t to_int64t(const T& t, std::false_type) 
{ 
    return t.to_int64t(); 
} 

template<class T> 
int64_t to_int64t(const T& t) 
{ 
    return to_int64t(t, std::is_integral<T>()); 
} 

int main() 
{ 
    int64_t i = 64; 
    auto x = to_int64t(i); 
} 

Inną możliwością jest zastosowanie klasycznej techniki SFINAE opartej na std::enable_if. To, w jaki sposób mogłaby wyglądać (zauważ, że od C++ 11, argumenty Domyślny szablon na szablonach funkcyjnych są dozwolone):

#include <type_traits> 
#include <cstdint> 

template<class T, typename std::enable_if< 
    std::is_integral<T>::value>::type* = nullptr> 
int64_t to_int64t(const T& t) 
{ 
    return t; 
} 

template<class T, typename std::enable_if< 
    !std::is_integral<T>::value>::type* = nullptr> 
int64_t to_int64t(const T& t) 
{ 
    return t.to_int64t(); 
} 

int main() 
{ 
    int64_t i = 64; 
    auto x = to_int64t(i); 
} 

Jeszcze inna możliwość, choć bardziej gadatliwy, jest zdefiniowanie szablonów klas pomocnika (który może być częściowo specjalistyczne) w detail nazw i zapewnić globalne spedytora - nie chciałbym używać tej techniki w tym przypadku zastosowania, ale pokazuję, bo to może się przydać w pokrewnych sytuacjach konstrukcja:

#include <type_traits> 
#include <cstdint> 

namespace detail 
{ 
    template<class T, bool = std::is_integral<T>::value> 
    struct helper { }; 

    template<class T> 
    struct helper<T, true> 
    { 
     static int64_t to_int64t(const T& t) 
     { 
      return t; 
     } 
    }; 

    template<class T> 
    struct helper<T, false> 
    { 
     static int64_t to_int64t(const T& t) 
     { 
      return t.to_int64t(); 
     } 
    }; 
} 

template<class T> 
int64_t to_int64t(const T& t) 
{ 
    return detail::helper<T>::to_int64t(t); 
} 

int main() 
{ 
    int64_t i = 64; 
    auto x = to_int64t(i); 
} 
+0

+1 t y - Spróbuję tego. – kfmfe04

+0

O mój Boże, to jest piękne. :) – 0x499602D2

+0

@PeteBecker: Dziękuję za edytowanie :) –

5

można po prostu użyć std::enable_if:

template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> 
int64_t to_int64t(const T& t) 
{ 
     return t; 
} 

template<class T, typename std::enable_if<!std::is_integral<T>::value, int>::type = 0> 
int64_t to_int64t(const T& t) 
{ 
     return t.to_int64t(); 
} 
Powiązane problemy