C++ SFINAE不与std::基础_类型一起发生

C++ SFINAE不与std::基础_类型一起发生,c++,enums,variadic-templates,sfinae,overload-resolution,C++,Enums,Variadic Templates,Sfinae,Overload Resolution,下面是使用clang 3.7.1和C++14编译的带有可变模板的SFINAE代码: #include <array> #include <iostream> #include <vector> #include <cstdint> enum class Bar : uint8_t { ay, bee, see }; struct S { static void foo() {} // std::begin(h) is defined

下面是使用clang 3.7.1和C++14编译的带有可变模板的SFINAE代码:

#include <array>
#include <iostream>
#include <vector>
#include <cstdint>

enum class Bar : uint8_t {
    ay, bee, see
};

struct S {

static void foo() {}

// std::begin(h) is defined for h of type H
template<typename H, typename... T>
static typename std::enable_if<std::is_pointer<decltype(std::begin(std::declval<H>()))*>::value>::type 
foo(const H&, T&&... t) 
{ std::cout << "container\n"; foo(std::forward<T>(t)...); }

// H is integral
template<typename H, typename... T>
static typename std::enable_if<std::is_integral<typename std::remove_reference<H>::type>::value>::type 
foo(const H&, T&&... t) 
{ std::cout << "integer\n"; foo(std::forward<T>(t)...); }

// H is an enum with underlying type = uint8_t
/*
template<typename H, typename... T>
static typename std::enable_if<std::is_same<typename std::underlying_type<H>::type,uint8_t>::value>::type 
foo(const H&, T&&... t)
{ std::cout << "enum\n"; foo(std::forward<T>(t)...); }
*/
};


int main()
{
    S::foo(std::array<int,8>(), 5, 5L, std::vector<int>{}, 5L);
}
#包括
#包括
#包括
#包括
枚举类栏:uint8\t{
哎,蜜蜂,看到了吗
};
结构{
静态void foo(){}
//std::begin(h)是为h类型的h定义的
模板
静态类型名称std::enable_if::type
foo(常数H&,T&…T)
{std::cout对SFINAE不友好。尝试访问非枚举类型的
std::底层_type::type
会导致未定义的行为(通常是硬错误),而不是替换失败

在尝试访问其基础类型之前,您需要首先确定所讨论的类型是枚举类型。在第行中写入此内容将类似于
typename std::enable_if::type::type
。将返回类型中的
typename std::subground_type::type
。将返回类型中的
得到一个更可怕的混乱的工作:)

如果您发现自己需要经常这样做,或者只是不想编写
typename std::enable_If::type
,您可以编写一个SFINAE友好的
基础类型

template<class T, bool = std::is_enum<T>::value>
struct safe_underlying_type : std::underlying_type<T> {};
template<class T>
struct safe_underlying_type<T, false /* is_enum */> {};
模板
结构安全_基础_类型:std::基础_类型{};
模板
结构安全\u基础\u类型{};

以下是一个解决方案,其灵感来源于我的用例:

template <typename T, bool = std::is_enum<T>::value>
struct relaxed_underlying_type {
    using type = typename std::underlying_type<T>::type;
};

template <typename T>
struct relaxed_underlying_type<T, false> {
    using type = T;
};
模板
结构松弛\u基础\u类型{
使用type=typename std::底层类型::type;
};
模板
结构松弛\u基础\u类型{
使用类型=T;
};
用法示例:

template <typename T>
struct UnwrapEnum {
    using type =
        typename std::conditional<
        std::is_enum<T>::value,
        typename relaxed_underlying_type<T>::type,
        T>
        ::type;
};

enum class MyEnum : int {};

class MyClass {};

int main() {
    UnwrapEnum<MyEnum>::type x;
    static_assert(std::is_same<decltype(x), int>::value);

    UnwrapEnum<MyClass>::type y;
    static_assert(std::is_same<decltype(y), MyClass>::value);

    return 0;
}

模板
结构展开{
使用类型=
类型名称std::条件<
std::is_enum::value,
typename\u基础\u类型::类型,
T>
::类型;
};
枚举类MyEnum:int{};
类MyClass{};
int main(){
展开:x型;
静态断言(std::is\u same::value);
展开::类型y;
静态断言(std::is\u same::value);
返回0;
}

为什么不直接使用
std::enable_if::type
?它。是否只针对底层类型为
uint8\t
enum
s?在这种情况下,您可以再添加一个条件
sizeof(H)==sizeof(uint8\t)
。即
std::is_enum::value&(sizeof(H)==sizeof(uint8\t))
。上面的ideone示例中已经介绍了这一点。@iammilind:好建议,谢谢