Restrict Template Function

Restrict Template Function

The only way to restrict a template is to make it so that it uses something from the types that you want, that other types don't have.

So, you construct with an int, use + and +=, call a copy constructor, etc.

Any type that has all of these will work with your function -- so, if I create a new type that has these features, your function will work on it -- which is great, isn't it?

If you want to restrict it more, use more functions that only are defined for the type you want.

Another way to implement this is by creating a traits template -- something like this

template<class T>
SumTraits
{
public:
const static bool canUseSum = false;
}

And then specialize it for the classes you want to be ok:

template<>
class SumTraits<int>
{
public:
const static bool canUseSum = true;
};

Then in your code, you can write

if (!SumTraits<T>::canUseSum) {
// throw something here
}

edit: as mentioned in the comments, you can use BOOST_STATIC_ASSERT to make it a compile-time check instead of a run-time one

How do I restrict templates to specific types?

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.

c++ function template restrict parameter type

Using enable_if you could write the function like

template <typename arg_t, std::enable_if_t<std::is_same_v<std::decay_t<arg_t>, int> ||
std::is_same_v<std::decay_t<arg_t>, std::string>,
bool> = true>
void func(arg_t arg){}

C++ templates that accept only certain types

I suggest using Boost's static assert feature in concert with is_base_of from the Boost Type Traits library:

template<typename T>
class ObservableList {
BOOST_STATIC_ASSERT((is_base_of<List, T>::value)); //Yes, the double parentheses are needed, otherwise the comma will be seen as macro argument separator
...
};

In some other, simpler cases, you can simply forward-declare a global template, but only define (explicitly or partially specialise) it for the valid types:

template<typename T> class my_template;     // Declare, but don't define

// int is a valid type
template<> class my_template<int> {
...
};

// All pointer types are valid
template<typename T> class my_template<T*> {
...
};

// All other types are invalid, and will cause linker error messages.

[Minor EDIT 6/12/2013: Using a declared-but-not-defined template will result in linker, not compiler, error messages.]

How to restrict template class to only specific specializations with type aliases

Best scenario I would like to achieve would be to make Wrapper class not visible outside the usage of aliases I create.

This is possible using private and a wrapper class

class WrapperAccessor {
template < typename Type >
class Wrapper {
public:
Wrapper(Type* resource) : ptr(resource) {}
~Wrapper() { free(ptr); }

private:
Type* ptr;
};

public:
using Window = Wrapper<SDL_Window>;
using Renderer = Wrapper<SDL_Renderer>;
};

using Window = WrapperAccessor::Window;
using Renderer = WrapperAccessor::Renderer;

How to restrict a template function from being called if the type is not a pointer?

If you just want to find out, where your class is erroneously used with a non-pointer template parameter type, you can use static_assert:

template<class t>
class List {
static_assert(!std::is_pointer<t>::value, "Template parameter must be of pointer type");

//other stuff
};

If you want the ClearAndDelete() function to be usable with pointer and non-pointer types, you could e.g. use something like this:

template<class T>
void deleteIfPointer(const T& element) {}

template<class T>
void deleteIfPointer(T* ptr) {
delete ptr;
}

usage:

deleteIfPointer(ptr->Item); //instead of delete ptr->Item

On a side note: Usually containers should not delete objects that their elements point to (If you need this behavior, you might want to use std::unique_ptr instead).

Restrict function template to specific types?

The typical answer these days is this. To define the function with an extra template parameter that will make the function be ignored if the dummy type constructed from the expression doesn't exist.

template <typename T, typename = decltype(std::to_string(std::declval<T>()))>
std::string operator+(std::string & lhs, T && t)
{
...
}

It can be more refined by it does what you want.

Another more elegant syntax is this

template <typename T>
auto operator+(std::string & lhs, T && t) -> decltype(std::to_string(t))
{
...
}

This exploits a language feature called SFINAE.



Related Topics



Leave a reply



Submit