So with SFINAE and c++11, it is possible to implement two different template functions based on whether one of the template parameters can be substituted.
For exampl
I find the void_t
trick to be usually preferable to the traditional SFINAE method shown in the other answer.
template<class...> using void_t = void; // now in the C++17 working paper!
// GCC <= 4.9 workaround:
// template<class...> struct voider { using type = void; };
// template<class... T> using void_t = typename voider<T...>::type;
template<class, class = void>
struct is_ostreamable : std::false_type {};
template<class T>
struct is_ostreamable<T, void_t<decltype(std::declval<std::ostream&>() <<
std::declval<T>())>> : std::true_type {};
The partial specialization is selected if and only if the expression is well-formed.
Demo.
Note that the &
in std::declval<std::ostream&>()
is important, because otherwise std::declval<std::ostream>()
is an rvalue and you'll get ostream
's catchall rvalue stream insertion operator, and report that everything is streamable.
The above code checks for an operator<<
that can accept a T
rvalue . If you want to check for one that accepts an lvalue T
, then use std::declval<T&>()
.
Using SFINAE, it's possible like this:
template <typename T>
class has_ostream_lshift
{
struct no {};
template <typename T2>
static decltype(std::declval<std::ostream&>() << std::declval<T2>()) test(int);
template <typename T2>
static no test(...);
public:
enum { value = ! std::is_same<no, decltype(test<T>(0))>::value};
};