I tried to implement a type_traits able to detect if a class can be used in the context of an instruction such as: std::cout << my_class_instance;.
My implementation tried to benefit from SFINAE to detect whether or not the function std::ostream& operator<<(std::ostream&, const MyClass&) is available for the class. Unfortunately it fails under g++-4.9 which should be compatible with C++ 11. Other compilers does not complain and seem to generate the right code: g++-5+, clang++-3.3+ and also Visual Studio.
Here is the implementation I tried so far:
#include <iostream>
#include <type_traits>
#include <vector>
template <class... Ts> using void_t = void;
template <class T, class = void> struct can_be_printed : std::false_type {};
template <class T> struct can_be_printed<T, void_t<decltype(std::cout << std::declval<T>())>> : std::true_type {};
static_assert(!can_be_printed<std::vector<int>>::value, "vector<int> cannot be printed");
static_assert(can_be_printed<int>::value, "int can be printed");
Live example is available at: https://godbolt.org/g/6xFSef . Please do not hesitate if you need more details.
This is an issue with how gcc interprets:
before it handled the core language issue that specifically affected that (1558). Basically, gcc sees that this alias isn't affected by the template parameters and just drops in
void. That completely defeats the purpose ofvoid_tif it always succeeds, which is what is happening in this case.You can fool it by just wrapping
void_tin another template (as suggested in the original paper):Here, gcc can't just drop the substituation, since there is of course hypothetically some other
make_voidspecialization that isn't justvoid.