在实现检测存在相等运算符时,我注意到由于某些原因,下面的代码无法在GCC v4,...,v7上编译,但似乎在Clang中编译良好。确切的错误(下面)是由于GCC无法找到名称空间中模板化的重载运算符:
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
有趣的是,在函数foo
中使用相同的运算符在GCC和Clang中都很好。
我的问题是:哪个编译器就在这里?如果那是GCC那么为什么在这样的情况下找不到运算符重载是正确的呢?
#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;
}