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_t
if it always succeeds, which is what is happening in this case.You can fool it by just wrapping
void_t
in 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_void
specialization that isn't justvoid
.