I have a member function of a class in which I'd like to use perfect forwarding for one of the parameters. However, the function being forwarded to only accepts a single argument of type c2Type
, so I'd like the calling function also to only accept c2Type
arguments, but obviously have to keep the universal reference to do the forwarding. It seems it can be accomplished using a default template parameter like so:
class c2Type
{
// some data members...
};
template<typename T, typename isC2Type = typename std::enable_if<
std::is_same<c2Type, typename std::decay<T>::type>::value>::type>
void configurationMessageHandler(T&& message)
{
// some stuff...
mapAddress(std::forward<c2Type>(message));
}
mapAddress(c2Type&& message)
{
// do stuff...
};
However, I need to check for this type on several member functions, and also such a long template seems unfriendly and unreadable. What I'd like to is create an alias for isC2Type
like
template<typename T>
using isC2Type = typename std::enable_if<
std::is_same<c2Type, typename std::decay<T>::type>::value>::type;
which I thought would make the configurationMessageHandler
template look like
template<typename T, isC2Type<T>>
but that doesn't compile. How can I properly use aliases in this case?
I hope this can help you.
template<class U, class T,
class= std::enable_if_t<std::is_same<std::decay_t<T>, U>::value, T>>
using LimitTo = T;
template<class T>
void configurationMessageHandler(LimitTo<c2Type,T>&& message){
// some stuff...
mapAddress(std::forward<T>(message));
//!! Use T because the reference of c2Type maybe has cv-qualify
}
Even when there are many parameters, for example:
void foo(int);
template<class A, class B, class C>
void foo(LimitTo<int,A>&& , LimitTo<float,B>&& , LimitTo<bool,C>&& );
template<class T>
void foo(LimitTo<string,T>&& );
However, there are some pitfalls with this trick:
Be careful that in some cases it won't work. This leads to fatal errors in some compilers. I don't know why.
template<class...Args>
void foo(LimitTo<double,Args>&&... args){}
Use default parameters to avoid ambiguities, e.g. with regards to such constructors:
template<class T>
Ctor(LimitTo<string,T>&&,string* =nullptr) {} //string* or anything else
template<class T>
Ctor(LimitTo<double,T>&&, double* =nullptr) {}
Inherited constructors will cause some problems as default parameters can't be inherited. So change it to:
template<class T>
Ctor(LimitTo<string,T>&&,string*) {}
template<class T>
Ctor(LimitTo<double,T>&&, double*) {}