dimanche 26 novembre 2017

overload operators template resolution in namespace inside template declarations

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