Problem: I am developing a program with C++11. I want to write a function that accept both rvalue reference and lvalue reference. (i.e. universal reference).
The following function accept a universal reference parameter:
template<class T> void function(T&& t){/*SNIP*/}
However, it accepts all type of parameter. It ruins the type safety of the function. What should I do if I want it to accept a specific type of parameter?
Here is a solution that I can think of:
void function(Class& t){/*SNIP*/}
void function(Class&& t){ function(t); }
However, it's ugly. In case I want to change the parameter to be accepted, or changing the function name, I have to update both version of the function. It there a better equivalent than this?
EDIT: Problem solved. You both have answered quite well. I have voted +1 to both answers to show my appreciation. I am going to leave this question for a few days. The answer with the most votes will be accepted.
EDIT2: I end up with the following code:
template < class T,
class=typename std::enable_if<std::is_same<Class, typename std::decay<T>::type>::value>::type //Dummy template parameter
>
void function(T&&){}
EDIT3: I have written a macro definition for this purpose:
#define uRefType(T, typeLimit) class T, class=typename std::enable_if<std::is_same<typename std::decay<T>::type, typeLimit>::value>::type
Usage example:
template< uRefType(T, Class) > void function(T&&){}
One way of doing this is to use
std::enable_if
. That's a struct provided by thetype_traits
header. It is defined in such a way thatenable_if<A,B>::type
is the typeB
if the boolean conditionA
evaluates to true at compile time. Otherwise it is empty.Hence, if you have a function template
and you want to ensure it is only defined if
T
is a certain type, you can use theenable_if<...>::type
construct instead of the return type (here,void
). The boolean conditionA
is then defined as something like:T
isint
, and the typeB
is defined as the original return type of the function (here,void
).So, if we want
fun
to be defined only ifT
isint
, we get this:Notice how the boolean condition is defined as follows (omitting
std::
to for better readability):The
decay
statement is used to ensure this works regardless of whetherT
isint
orint &
(and a few more special cases).Further remarks: This sort of trick is only really useful if the definition of the function in question is the same for both rvalue and lvalue. In many cases that won't be the case (because the rvalue case will implement a move, the lvalue won't, or something similar).
A typical situation where both definitions are in fact the same is when the function body is very short and does nothing but forwarding the argument(s) to yet another (possibly overloaded) function call:
In that case it is probably ok not to use any
enable_if
or other trick, because the declaration ofother_fun
will ensure that ultimately only certain types will be accepted.Use
std::enable_if
withstd::is_same
:And (as first stated in jogojapan's answer, which I forgot to mention) use
std::decay
onT
, asT&
is not the same type as aT
andconst T
is not the same as T`:See demo at http://ideone.com/ztkHsf .