2013-05-29 14 views
5

W funkcji w klasie szablonu próbuję rozróżnić typy pierwotne i inne.C++: alternatywa dla 'std :: is_fundamental'?

w C++ 11 można zrobić:

if(std::is_fundamental<T>::value) 
{ 
    // Treat it as a primitive 
} 
else 
{ 
    //Treat it otherwise 
} 

Proszę mnie poprawić jeśli się mylę i to nie tylko w C++ 11.

Czy istnieje alternatywa do tego we wcześniejszych wersjach C++ ?

Odpowiedz

8

Można użyć Boost's type traits w C++ 03 tak:

#include <boost/type_traits/is_fundamental.hpp> 

... 

if(boost::is_fundamental<T>::value) 
{ 
    // Treat it as a primitive 
} 
else 
{ 
    //Treat it otherwise 
} 

Chyba to powinno działać dla C++ 98, jak również.

+0

Dzięki. +1 dla "włączenia". – Subway

2

Przy pomocy tego kodu będziesz mieć problemy. Jeśli chcesz rozróżnić różne cechy typu, należy to zrobić w czasie kompilacji, a nie w czasie wykonywania. W zależności od wykonywanej operacji jedna z dwóch gałęzi twojego if może nie zostać skompilowana. Więc lepiej jest przekazać do wyspecjalizowanej funkcji:

void operation_impl(boost::true_type /*other params*/) { 
    // Treat it is primitive 
} 

void operation_impl(boost::false_type /*other params*/) { 
    // Treat it otherwise 
} 

template<class T> 
void operation(/* params*/) { 
    operation_impl(boost::is_fundamental<T>::type() /*other params*/); 
} 

Dzięki tej technice realizacji tylko używane oddział musi skompilować (to znaczy być poprawne).

Edit:

Oto niektóre dodatkowe informacje. Rozwiązanie tego problemu wiąże się z instancją szablonów. Przełączam się z is_fundamental na is_array, aby pokazać, jak operacje mogą się nie udać.

Zacznijmy od pierwszego przykładu:

template <class T> 
void fun(T t) { 
    if(boost::is_array<T>::value) 
    { 
     std::cout << "true" << std::endl; 
    } 
    else 
    { 
     std::cout << "false" << std::endl; 
    } 
} 

void f(int i) { 
    fun(i); 
} 

To będzie skompilować i uruchomić i kompilator będzie widać, że tylko jeden oddział if zostaną wykorzystane i usunie drugi jako niewykorzystany kod.

W moim drugim przykładzie zrobię someithing w przypadku używam operację tablicy:

template<class T> 
void fun(T& t) { 
    if(boost::is_array<T>::value) 
    { 
     std::cout << t[0]; 
    } 
    else 
    { 
     std::cout << t; 
    } 
} 

void f(int i) { 
    fun(i); 
} 

Teraz nie będzie skompilować. Powód jest z int jako szablon argumentem t[0] jest źle sformułowany. Nie możesz użyć tej instrukcji środowiska wykonawczego do rozróżnienia właściwości typów w czasie kompilacji, które są potrzebne w kodzie (w tym przykładzie właściwość tablicy i użycie t[0]).

W trzecim przykładzie będziemy disitinguish na czasie kompilacji za pomocą funkcji przeciążenia:

template<class T> 
void fun_impl(boost::true_type, T& t) { 
    std::cout << t[0]; 
} 

template<class T> 
void fun_impl(boost::false_type, T& t) { 
    std::cout << t; 
} 

template<class T> 
void fun(T& t) { 
    fun_impl(typename boost::is_array<T>::type(),t); 
} 

void f(int i) { 
    fun(i); 
} 

Tutaj is_array<T>::type jest albo true_type lub false_type. Wynik ten jest używany jako selektor do wyboru właściwego przeciążenia fun_impl w czasie kompilacji i tylko wybrane przeciążenie jest instanziowane i kompilowane.

Zwykle takie techniki są wykorzystywane do wyboru w dogodnym dla siebie terminie najlepszego wykonania, które może być kompilowane tylko wtedy, gdy typy mają określone właściwości.

2-ty edit:

ten ulegnie oczywiście zmianie jeśli static if jest częścią języka.

+0

Czy mógłbyś omówić problem, który mógłbym napotkać w innym podejściu? Czy możesz dodać odniesienie do wyjaśnienia? Nie rozumiem, co napisałeś. – Subway

+0

Dziękujemy! +1 do opracowania. Wciąż jednak mam pytanie: jak rozumiem, twoim celem jest skompilowanie kodu i zapisanie kompilacji niepotrzebnego kodu. Biorąc pod uwagę, że mój kod się kompiluje, czy istnieją rzeczywiste problemy (takie jak nieoczekiwane zachowanie), które mogą napotkać w czasie wykonywania przy użyciu pierwszego podejścia? – Subway

+0

@Subway nie, myślę, że kompilator widzi twój boost :: is_fundamental :: wartość jako stałą i usunie nieużywany kod, więc nie ma narzutów środowiska wykonawczego i żadnych UB. Podejście polega na skompilowaniu go w ogóle. Człon const jest przeznaczony do używania ze std :: enable_if (jako integralny argument szablonu) i oczywiście do demonstracji (np. Drukowania wartości). Myślę, że do każdego innego celu powinieneś wybrać się na wycieczkę poprzez przeciążenie funkcji. –