简体   繁体   中英

Unexpected template matching with std::void_t in VC++

I have this code: https://ideone.com/dUkfjp

#include <type_traits>

namespace details
{

template <typename T, typename U = T>
using equality_compare_ret_t = decltype(std::declval<T>() == std::declval<U>());

template <typename T, typename U = T>
using not_equality_compare_ret_t = decltype(std::declval<T>() != std::declval<U>());

};//end namespace details

template <typename, typename = std::void_t<>>
struct is_equality_comparable
    : std::false_type
{};

template <typename T>
struct is_equality_comparable<T,
    std::void_t<
        details::equality_compare_ret_t<std::remove_reference_t<T>>,
        details::not_equality_compare_ret_t<std::remove_reference_t<T>>
    >>
    : std::true_type
{};

template <typename T>
constexpr bool is_equality_comparable_v = is_equality_comparable<T>::value;


struct default_constuctible
{
    constexpr default_constuctible()
    {}
};

bool operator==(const default_constuctible&, const default_constuctible&)
{
    return true;
}
bool operator!=(const default_constuctible&, const default_constuctible&)
{
    return false;
}

static_assert(is_equality_comparable<default_constuctible>::value, "false");

Compiles with defaults on ideone C++14 (gcc 6.3)

The same code in godbolt.org compiles with clang 6.0.0 and gcc 8.1 and don't compiles with MSVC 19 2017 RTW.

Don't compiles because of the last line code:

static_assert(is_equality_comparable<default_constuctible>::value, "false");

In MSVC is_equality_comparable<default_constuctible>::value is evaluated as false and in clang/gcc is evaluted as true. Same problem I have in MSVC 2017 community edition 15.7.3.

I don't understand why, bug in MSVC or in my code?

fixed with

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

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

better solution (compiles in vc++ 15.7.3, doesn't compile in msvc 19 2017 rtw):

#include <type_traits>

namespace details
{

template <typename T, typename U>
using equality_compare_with_ret_t = decltype(std::declval<T>() == std::declval<U>());

template <typename T, typename U>
using not_equality_compare_with_ret_t = decltype(std::declval<T>() != std::declval<U>());

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

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

};//end namespace details

template <typename, typename, typename = std::void_t<>>
struct is_equality_comparable_with
    : std::false_type
{};

template <typename T, typename U>
struct is_equality_comparable_with<T, U,
    std::void_t<
        details::equality_compare_with_ret_t<std::remove_reference_t<T>, std::remove_reference_t<U>>,
        details::not_equality_compare_with_ret_t<std::remove_reference_t<T>, std::remove_reference_t<U>>
    >>
    : std::true_type
{};

template <typename T, typename U>
constexpr bool is_equality_comparable_with_v = is_equality_comparable_with<T, U>::value;

template <typename, typename = std::void_t<>>
struct is_equality_comparable
    : std::false_type
{};

template <typename T>
struct is_equality_comparable<T,
    std::void_t<
        details::equality_compare_ret_t<std::remove_reference_t<T>>,
        details::not_equality_compare_ret_t<std::remove_reference_t<T>>
    >>
    : std::true_type
{};

template <typename T>
constexpr bool is_equality_comparable_v = is_equality_comparable<T>::value;


struct default_constuctible
{
    constexpr default_constuctible()
    {}
};

bool operator==(const default_constuctible&, const default_constuctible&)
{
    return true;
}
bool operator!=(const default_constuctible&, const default_constuctible&)
{
    return false;
}
bool operator==(const default_constuctible&, int)
{
    return true;
}
bool operator!=(const default_constuctible&, int)
{
    return false;
}

static_assert(is_equality_comparable<default_constuctible>::value, "false");
static_assert(is_equality_comparable_with<default_constuctible, int>::value, "false");
static_assert(!is_equality_comparable_with<default_constuctible, char*>::value, "false");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM