Search code examples
c++templatesc++17stdvectorsfinae

Detection of free '==' operator using std::experimental::is_detected_v : different behavior for std classes


I am trying to detect at compile time if some classes do have the 'equals to' operator defined. I don't understand the behavior of the following snippet:

#include <iostream>
#include <vector>
#include <experimental/type_traits>

template<typename T>
using SupportsEqualsToOp_t = decltype(std::declval<T>().operator==(std::declval<T>()));

template<typename T>
using SupportsEqualsToFree_t = decltype(std::declval<T>() == std::declval<T>());

template<typename T>
struct A{};

int main() {

    std::vector<int> v0{1,2,3};
    std::vector<int> v1{1,2,3};

    //std::cout << v0==v1 << std::endl; // this does not compile

    std::cout << std::experimental::is_detected_v<SupportsEqualsToOp_t, std::vector<int>> << std::endl;
    std::cout << std::experimental::is_detected_v<SupportsEqualsToFree_t, std::vector<int>> << std::endl;

    std::cout << std::experimental::is_detected_v<SupportsEqualsToOp_t, A<int>> << std::endl;
    std::cout << std::experimental::is_detected_v<SupportsEqualsToFree_t, A<int>> << std::endl;

    return 0;
}

Which gives:

0
1
0
0

Whereas I would expect to have:

0
0
0
0

Why std::vector does not behave as A here?


Solution

  • You've messed up your operator precedence. std::cout << v0 doesn't compile, nor would (std::cout << v0) == v1

    Not only that, your SupportsEqualsToFree_t finds any ==, not just free function ==.

    If you want specifically free function ==, you need something like

    template<typename T>
    using SupportsEqualsToOp_t = decltype(std::declval<T>().operator==(std::declval<T>()));
    
    template<typename T>
    using SupportsEqualsToFree_t = decltype(operator==(std::declval<T>(), std::declval<T>()));
    
    template<typename T>
    using SupportsEqualsTo_t = decltype(std::declval<T>() == std::declval<T>());
    

    See it live