I want to use type traits to check if operator <<
is defined for some classes.
So I've defined 2 classes A
and B
which are similar but the operator <<
is overloaded only for A
.
To do that I am making use of boost::is_detected
.
The running code is the following:
#include<iostream>
#include <boost/type_traits/is_detected.hpp>
class A
{
public:
std::string name;
int64_t age;
bool b;
};
class B
{
public:
std::string name;
int64_t age;
bool b;
};
std::ostream& operator<<(std::ostream& destination, const A& type)
{
return destination << "name=" << type.name << ", age=" << int(type.age)<<std::endl;
}
template <typename T>
using has_operator_insertion_check = decltype(void(&std::decay_t<T>::operator<<));
template <typename T>
using has_operator_insertion = boost::is_detected<has_operator_insertion_check, T>;
template <typename T>
constexpr bool has_operator_insertion_v = has_operator_insertion<T>::value;
int main()
{
A a, b;
a.name = "Ciaooooo";
a.age = 65536;
a.b = true;
std::cout<<"A has operator '<<'? "<<has_operator_insertion_v<A><<std::endl;
std::cout<<"B has operator '<<'? "<<has_operator_insertion_v<B><<std::endl;
return 0;
}
However, this is not working and the output I am getting is:
A has operator '<<'? 0
B has operator '<<'? 0
Why am I getting identical results?
std::ostream& operator<<(std::ostream& destination, const A& type)
is a free function, not a member function and
decltype(void(&std::decay_t<T>::operator<<));
only checks for the presence of a member function.
You can rewrite your type trait to work with member and non-member output operators like
// false case
template <typename T, typename = void>
struct has_operator_insertion_check : std::false_type {};
// partial specialization,
// if std::declval<std::ostream&>() << std::declval<T>() is valid then true
template <typename T>
struct has_operator_insertion_check<T, std::void_t<decltype((std::declval<std::ostream&>() << std::declval<T>()))>> : std::true_type {};
template <typename T>
constexpr bool has_operator_insertion_v = has_operator_insertion_check<T>::value;
You can see this working in this live example.