C++ std::conditional_t 不会与 std::is_enum_v 和 std::underlying_type_t 一起编译

Sym*_*ink 4 c++ metaprogramming type-traits

我正在尝试编写可以索引到例如 an 的类型的类型特征std::vector,其中应该包括枚举类型,因为我可以将它们转换为它们的基础类型。

到目前为止我已经写了以下特征。

#include <iostream>
#include <type_traits>
#include <cinttypes>
#include <vector>
#include <utility>

template<typename T>
struct is_unsigned_integral :
    std::integral_constant<
        bool,
        std::is_integral<T>::value &&
        std::is_unsigned<T>::value
    > {};

template<typename T>
inline constexpr auto is_unsigned_integral_v = 
    is_unsigned_integral<T>::value;

template<typename, typename = void>
struct is_index : std::false_type {};

template<typename T>
struct is_index<
    T, 
    std::enable_if_t<
        is_unsigned_integral_v<
            std::conditional_t<
                std::is_enum_v<T>,
                std::underlying_type_t<T>,
                T
            >
        >
    >
> : std::true_type {};

template<typename T>
inline constexpr auto is_index_v = is_index<T>::value;

enum class idx : unsigned int {};

int main() {
    static_assert(is_index_v<unsigned int>, "");
    static_assert(is_index_v<idx>, "");
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但我收到以下错误消息

type_traits:2009:15: error: 
      only enumeration types have underlying types
      typedef __underlying_type(_Tp) type;
Run Code Online (Sandbox Code Playgroud)

我期望以下内容

std::conditional_t<
    std::is_enum_v<T>,
    std::underlying_type_t<T>,
    T
>
Run Code Online (Sandbox Code Playgroud)

评估八个T或底层类型是Tis an enum

我该如何做这个工作?

for*_*818 5

替换失败,因为没有std::underlying_type_t<unsigned int>.

您可以单独专攻:

#include <iostream>
#include <type_traits>
#include <cinttypes>
#include <vector>
#include <utility>

template<typename T>
struct is_unsigned_integral :
    std::integral_constant<
        bool,
        std::is_integral<T>::value &&
        std::is_unsigned<T>::value
    > {};

template<typename T>
inline constexpr auto is_unsigned_integral_v = 
    is_unsigned_integral<T>::value;

template<typename, typename = void>
struct is_index : std::false_type {};

template<typename T>
struct is_index<
    T, 
    std::enable_if_t< is_unsigned_integral_v<T> >    
> : std::true_type {};

template <typename T>
struct is_index<T,std::enable_if_t<std::is_enum_v<T> >> : is_index<std::underlying_type_t<T> > {};


template<typename T>
inline constexpr auto is_index_v = is_index<T>::value;

enum class idx : unsigned int {};

int main() {
    static_assert(is_index_v<unsigned int>, "");
    static_assert(is_index_v<idx>, "");
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

PS:来自cppreference/std::underlying_type

如果 T 是完整枚举 (enum) 类型,则提供一个成员 typedef 类型来命名 T 的基础类型。

否则,行为是未定义的。(直到 C++20)

否则,如果 T 不是枚举类型,则不存在成员类型。否则(T 是不完全枚举类型),程序格式错误。(自 C++20 起)

我必须承认,我不确定在您的示例中未定义的行为(C++20 之前)如何与 SFINAE 一起使用。不过,请注意,这在上面不是问题,因为它仅在实际上是枚举类型std::underlying_type_t<T>时使用。T