Phil C
Phil C

Reputation: 149

How do I restrict templates to specific types?

For simplicity, say I usually want to pass in strings and basic data types in here:

template <typename T>
void writeLine(const T &ob)
{
    std::cout << ob << std::endl;
}

In most cases, I would pass std::string, int, char, float, etc. But say that I don't want it to accept floats. In real world scenarios, I may not want it to accept certain classes.

Is there a way to restrict what the template type accepts?

Upvotes: 4

Views: 8423

Answers (1)

super
super

Reputation: 12928

Yes you can, the most simple way for your example is to put a static_assert in your function.

template <typename T>
void writeLine(const T &ob)
{
    static_assert(!std::is_same<T, float>::value, "You can't use floats here");
    std::cout << ob << std::endl;
}

This will give you a compile time error if you try and use the function with a float.

Another option is called SFINAE and is used to make the template parameter deduction fail under certain circumstances.

Usually you use std::enable_if in combination with some templates from <type_traits> header. The same thing with SFINAE would look something like:

template <typename T, typename std::enable_if<!std::is_same<T, float>::value, int>::type = 0>
void writeLine(const T &ob)
{
    std::cout << ob << std::endl;
}

Let's break down typename std::enable_if<!std::is_same<T, float>::value, int>::type.

!std::is_same<T, float>::value is the condition here, if this condition is true this template will have a ::type, otherwise it will not.

After the condition we can specify what we want the type to be if the condition is true, in this case we use int. If this is not specified it will default to void.

So as long as we don't pass a float to this template, the second template parameter will be deduced to int = 0. If we pass in a float the deduction will simply fail and you will get a no matching function error showing the template as a candidate with failed deduction.

Upvotes: 13

Related Questions