tags:

views:

73

answers:

3

How can I specify what is required to be a valid template argument? What I mean is let's for example take something like this:

template<class T>
void f(const T& obj)
{
//do something with obj
} 

but I would like T to be only integer type so I would accept char, int, short unsigned etc but nothing else. Is there (I'm sure there is) a way to detect it what is provided as a template arg?
Thank you.

+3  A: 

Have a look at concept checking (http://www.boost.org/doc/libs/1_43_0/libs/concept_check/concept_check.htm).

Scharron
A-ha wants to disable/enable template instantiation based on type traits. Boost Concept Check Library is to decrypt template related compiler error messages. It doesn't do what A-ha wants. He wants to disable template instantiation for certain types even if they support all required concepts. For example, double may support everything he does within the function's body, but he doesn't want the template to be used with double type. Concept Check is not an appropriate solution. enable_if and type_traits are the way to go.
From his question : - "what is required to be a valid template argument". - "I would accept char, int, short unsigned etc but nothing else".(And btw, my answer is accepted ;-))
Scharron
+5  A: 

You can use boost::enable_if and boost::is_integral (also included in the TR1):

#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
f(const T & obj)
{
    ...
}
Luc Touraille
This is the way to go. Boost Concept Check Library is not appropriate.
+2  A: 

If you want non-integer types to cause a compilation error, you can also assert statically (compile-time assertions).

With C++0x:

#include <utility>

template <class T>
void foo(T )
{
    static_assert(std::is_integral<T>::value, "Only integral types allowed");
}

int main()
{
    foo(3);    //OK
    foo(3.14); //makes assertion fail
}

With C++03, boost will help:

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>

template <class T>
void foo(T )
{
    BOOST_STATIC_ASSERT(boost::is_integral<T>::value);
}

int main()
{
    foo(3);
    foo(3.14);
}

(IMO, enable_if is for scenarios where you want to enable some other version of the function for other types and avoid getting an error. If you want an error for all other types, having the function disabled, you might just get a not too helpful message: "no matching function to call", which doesn't even point to the place in the code where non-integers are disallowed.)

UncleBens
What is wrong with "no matching function to call" message? It will point to the place where a wrong argument plugged into the function. What else you want? enable_if is superior, because your solution will interfere with overload resolution. There may be foo(float) overload which could match foo(3.14), but which won't be called because the template function is selected over it.
@rn141: I said it depends. *If* there are not meant to be any other overloads, then "no matching function to call" is a rather vague diagnostic to get.
UncleBens
@UncleBens +2 I really like your answer.
There is nothing we can do