Question

Consider these two functions:

template <class Type, 
          class = typename std::enable_if</*HAS OPERATOR <<*/>::type>
void f(std::ostream& stream, const Type& value);

template <class Type, 
          class... DummyTypes,
          class = typename std::enable_if<sizeof...(DummyTypes) == 0>::type>
void f(std::ostream& stream, const Type& value, DummyTypes...);

As the non-variadic overload has the priority over the variadic overload, I want to check whether the type has the operator<< with an std::ostream using std::enable_if in the first version.

So what should I write instead of /*HAS OPERATOR <<*/ ?

Was it helpful?

Solution

The following should work

template <class Type, 
          class = decltype(std::declval<std::ostream&>() << std::declval<Type>())>
void f(std::ostream& stream, const Type& value)
{
    stream << value;
}

(note you don't need to use std::enable_if in this case)

OTHER TIPS

Using trailing return type (1), you can actually have a foretaste of concepts:

template <typename Type>
auto f(std::ostream& out, Type const& t) -> decltype(out << t, void()) {
    // ...
}

Because of SFINAE, this overload can only be selected if the type of out << t can be resolved, and this implies that an overload of << exists that accepts both parameters.

The one pitfall is that this does not work if you need the contrary, that is enabling a function if this overload does not exists. In this case an enable_if strategy (and the symmetric disable_if) is necessary, as far as I know.

(1) thanks to Simple for helping out with the syntax

It is easiest to check when you have the arguments around, i.e., I would rather try to use something like this:

template <typename Type>
auto f(std::ostream& out, Type const& value)
    -> typename std::enable_if<sizeof(out << value) != 0>::type {
    ...
}

A similar effect could be obtained using std::declval() but off-hand I'm not sure about creating references.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top