While implementing detection of presence of equality operators i noticed that for some reasons code below fail to compile on GCC v4, ..., v7 but seems to compile fine in Clang. The exact error (below) is due to inability of GCC to find overloaded operator templated inside the namespace:
stackoverflow-operator.cpp:15:51: error: no match for 'operator==' (operand types are 'A' and 'A')
std::is_same<bool, decltype(std::declval<T>() == std::declval<T>())>::value and
stackoverflow-operator.cpp:16:51: error: no match for 'operator!=' (operand types are 'A' and 'A')
std::is_same<bool, decltype(std::declval<T>() != std::declval<T> ())>::value
Interestingly using the same operator inside the function foo
is fine in both GCC and Clang.
My question is: which compiler is right here? And if that is GCC then why it is right not to find operator overloads in cases like this?
#include <type_traits>
#include <iostream>
struct A {};
namespace has_equal_operator_impl {
struct NoEqualOperator {};
template<typename T1, typename T2> NoEqualOperator operator== (T1, T2) { return NoEqualOperator(); }
template<typename T1, typename T2> NoEqualOperator operator!= (T1, T2) { return NoEqualOperator(); }
template<typename T>
typename std::enable_if<
std::is_same<bool, decltype(std::declval<T>() == std::declval<T>())>::value and
std::is_same<bool, decltype(std::declval<T>() != std::declval<T>())>::value
, bool>::type
constexpr has_equal_operator()
{
return true;
}
template<typename T>
typename std::enable_if<
not (std::is_same<bool, decltype(std::declval<T>() == std::declval<T>())>::value and
std::is_same<bool, decltype(std::declval<T>() != std::declval<T>())>::value )
, bool>::type
constexpr has_equal_operator()
{
return false;
}
void foo()
{
auto r = A() == A(); // somehow this works just fine in GCC
}
}
int main()
{
// Only work in Clang and does not work in GCC because local namespace operators is not consider
std::cout << "has_equal_operator<int>() --> " << has_equal_operator_impl::has_equal_operator<int>() << std::endl;
std::cout << "has_equal_operator<A>() --> " << has_equal_operator_impl::has_equal_operator<A>() << std::endl;
return 0;
}
Aucun commentaire:
Enregistrer un commentaire