tags:

views:

173

answers:

3

In the description of some std template function I saw something like:

if the template parameter is of integral type, the behavior is such and such.
otherwise, it is such and such.

How can I do a similar test? Perhaps dynamic_cast?

Since the function I write is for my personal use I can rely on myself to supply only correct parameters, but why miss a chance to learn something? :)

+3  A: 

One possibility:

#include <type_traits> 
#include <iostream> 

struct trivial 
{ 
    int val; 
}; 

int main() 
{ 
    std::cout << "is_integral<trivial> == " << std::boolalpha 
        << std::is_integral<trivial>::value << std::endl; 
    std::cout << "is_integral<int> == " << std::boolalpha 
        << std::is_integral<int>::value << std::endl; 
    std::cout << "is_integral<float> == " << std::boolalpha 
        << std::is_integral<float>::value << std::endl; 

    return (0); 
} 

So you then use std::is_integral<> to determine the action.

graham.reeds
A: 

Boost.TypeTraits provides is_integral<>(), as described in another response, if your compiler does not yet support C++ features of the next standard.

gregg
probably not, I've just checked that I don't have the type_traits include file. should have added 'linux' and 'gcc' tags...
davka
@davka: Those tags have nothing to do with boost. If the header is missing, then you either need to add the right location to the search path for headers or install boost.
Roger Pate
+4  A: 

In addition to the other answers, it should be noted that the test can be used at runtime but also at compile-time to select the correct implementation depending on wether the type is integral or not:

Runtime version:

// Include either <boost/type_traits/is_integral.hpp> (if using Boost) 
// or <type_traits> (if using c++1x)
// In the following, is_integral shoudl be prefixed by either boost:: or std::

template <typename T>
void algorithm(const T & t)
{
    // some code

    if (is_integral<T>::value)
    {
        // operations to perform if T is an integral type
    }
    else
    {
        // operations to perform if T is not an integral type
    }

    // some other code
}

However, this solution can be improved when the implementation of the algorithm greatly depends on the test. In this case, we would have the test at the top of the function, then a big then block and a big else block. A common approach in this case is to overload the function and make the compiler select the correct implementation using SFINAE. An easy way to do this is to use boost::enable_if:

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

template <typename T>
typename boost::enable_if<boost::is_integral<T> >::type
algorithm(const T & t)
{
    // implementation for integral types
}

template <typename T>
typename boost::disable_if<boost::is_integral<T> >::type
algorithm(const T & t)
{
    // implementation for non integral types
}

When invoking the algorithm function, the compiler will "select" the correct implementation depending on wether the template parameter is integral or not.

Luc Touraille
very useful, thanks
davka
I'd say every compiler worth its grain will eliminate the dead branch in your first example - its simple enough.
Georg Fritzsche
@Georg Fritzsche: this is true, that is why I did not say anything about a potential performance gain. Nevertheless, I think the overloading approach is clearer: the two implementations can evolve separately, and I found it better to discriminate between what is static (known/performed at compile-time) and what is dynamic (known/performed at runtime). But well, that may be because I spent too much time doing metaprogramming these last months!
Luc Touraille
@Georg Fritzsche: another important point is that the first solution is not always an option, because it could lead to compiler errors when trying to perform operations that are only possible for certain types. For example, in the integral-specialized algorithm, I can use bitwise operators; if I did that in the first example, all the types used to instantiate the function would need to provide support for these operators (which is something I would rather not impose to the users of my algorithm!).
Luc Touraille
I know, i didn't criticize anything else and would personally prefer the second version myself... Its just misleading to read *"runtime version"* when it will be most likely eliminated at compile-time anyway.
Georg Fritzsche