Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++: alternative to 'std::is_fundamental'?

In a function within a template class, I'm trying to distinguish between primitive types and others.

In c++ 11 you can do:

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

Please correct me if I'm wrong and this is not only in c++ 11.

Is there an alternative to this in earlier versions of c++?

like image 891
Subway Avatar asked May 29 '13 06:05

Subway


2 Answers

You could use Boost's type traits in C++03 like this:

#include  <boost/type_traits/is_fundamental.hpp>

...

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

I guess this should work for C++98 as well.

like image 138
djf Avatar answered Oct 23 '22 11:10

djf


With this code you will likly have trouble. If you need to distinguish between different type traits this must be done at compile time, not at run time. Depending on what operations you are performing one of the two branches of your if may not compile. So it is better to forward to an specialized function:

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*/);
}

With this implementation technique only the used branch needs to compile (i.e. be correct).

Edit:

Here are some additional informations. The solution to this problem have to do with instanciation of templates. I switch from is_fundamental to is_array to show how operations may fail.

Lets start with the first example:

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

It will compile and run and the compiler will see that only one branch of the if statement will be used and will remove the other as unused code.

In my second example I will do someithing in the case I use an array operation:

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

Now it will not compile. The reason is with the int as an template argument t[0]is ill formed. You cant use this runtime statement to distinguish on type properties at compile time which are needed in your code (in this example the property of beeing an array and the use of t[0]).

In the third example we will disitinguish on compile time via function overloading:

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

Here is_array<T>::type is either true_type or false_type. This result is used as a selector for choosing the right overload of fun_impl at compile time and only the choosen overload is instanziated and compiled.

Normaly such techniques are used to select at comopile time a best implementation which may be only compilable if the types have certain properties.

2nd edit:

This will of course change if static if is part of the language.

like image 28
Jan Herrmann Avatar answered Oct 23 '22 11:10

Jan Herrmann