Conditional overloading with trailing-return-type possible?

2.2k views Asked by At

Suppose you attempt to do the following:

template</* args */>
typename std::enable_if< /*conditional*/ , /*type*/ >::type
static auto hope( /*args*/) -> decltype( /*return expr*/ )
{
}

Is it possible to combine conditional inclusion/overloading (std::enable_if) with trailing-return-type (auto ... -> decltype())?

I would not be interesting in solutions using the preprocessor. I can always do things like

#define RET(t) --> decltype(t) { return t; }

and extend it to take also the whole conditional. Instead I am interested if the language supports it without using another trait for the return type, i.e. ReturnType<A,B>::type_t or whatever is used in the function body.

2

There are 2 answers

5
Xeo On BEST ANSWER

The trailing-return-type isn't much different from the normal return type, except that it's specified after the parameter list and cv-/ref-qualifiers. Also, it doesn't necessarily need decltype, a normal type is fine too:

auto answer() -> int{ return 42; }

So by now you should see what the answer to your question is:

template<class T>
using Apply = typename T::type; // I don't like to spell this out

template</* args */>
static auto hope( /*args*/)
    -> Apply<std::enable_if</* condition */, decltype( /*return expr*/ )>>
{
}

Though I personally prefer using just decltype and expression SFINAE, as long as the condition can be expressed as an expression (e.g., can you invoke a function on an object of a certain type):

template<class T>
static auto hope(T const& arg)
  -> decltype(arg.foo(), void())
{
  // ...
}
2
David Rodríguez - dribeas On

I can only assume that your original pseudo code is a function template, or otherwise SFINAE would not work altogether. Now if it is a template function, you can use an extra template argument that is defaulted and use SFINAE on that argument:

template <typename T, typename _ = typename std::enable_if< trait<T>::value >::type >
static auto function( T arg ) -> decltype( expression ) {
   // ...
}

I prefer this as it limits the use of SFINAE to the template clause and leaves a cleaner function signature. This is one of my favorite under-the-radar new features of C++11.