意外的模板与VC ++中的std :: void_t匹配

时间:2018-07-12 12:33:36

标签: c++ stl

我有以下代码: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");

在ideone C ++ 14(gcc 6.3)上使用默认值编译

godbolt.org中的相同代码可以使用clang 6.0.0和gcc 8.1进行编译,而不能使用MSVC 19 2017 RTW进行编译。

由于最后一行代码而不会编译:

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

在MSVC中,is_equality_comparable<default_constuctible>::value被评估为false,在clang / gcc中被评估为true。我在MSVC 2017社区版本15.7.3中遇到相同的问题。

我不明白为什么会出现MSVC或代码中的错误?

2 个答案:

答案 0 :(得分:0)

固定为

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>());

答案 1 :(得分:0)

更好的解决方案(在vc ++ 15.7.3中编译,在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");