I am trying to create a templated can_stream
struct that inherits from
std::false_type
or std::true_type
depending on whether operator<<
is defined for type T
.
#include <iostream>
struct S {
int i;
};
std::ostream& operator<< (std::ostream& os, S const& s) {
os << s.i << std::endl;
return os;
};
struct R {
int i;
};
template<
typename T,
typename Enable = void
> struct can_stream : std::false_type {
};
template<
typename T
> struct can_stream< T, decltype( operator<<( std::declval< std::ostream& >(), std::declval< T const& >())) > : std::true_type {
};
int main() {
std::cout << can_stream< int >::value << std::endl;
std::cout << can_stream< S >::value << std::endl;
std::cout << can_stream< R >::value << std::endl;
}
I thought the above program would produce
1
1
0
because:
- operator
<<
exists for bothint
andS
(sodecltype(...)
is well formed). - partially specialised template is a better match than the unspecialised template.
However, it produces:
0
0
0
Why?
std::declval< std::ostream& >() << std::declval< T const& >()
- Some built-in types are implemented bystd
as members ofostream
. If you want to detect those too, you can't assume the operator is not a member. The expression takes care of all that for you. – Custos