SFINAE not happening with std::underlying_type
SFINAE not happening with std::underlying_type
下面的带有可变模板的SFINAE代码使用clang 3.7.1、C++14很好地编译:
#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 << "containern"; 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 << "integern"; 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 << "enumn"; foo(std::forward<T>(t)...); }
*/
};
int main()
{
S::foo(std::array<int,8>(), 5, 5L, std::vector<int>{}, 5L);
}
我希望基于类型H
:递归调用foo
的正确重载
- 如果为类型为
H
的h
定义了std::begin(h)
,我希望要选择的过载编号1 - 如果
H
是一个"积分型",我想要重载数2
这是有效的。但是如果我为enum类型添加另一个重载(你可以尝试取消对第三个重载的注释),那么我得到:
错误:只有枚举类型具有基础类型
我同意只有enums有一个底层类型,因此为什么第三个重载(使用std::underlying_type
)不能去掉SFINAE-d?
std::underlying_type
对SFINAE不友好。尝试访问非枚举类型的std::underlying_type<T>::type
会导致未定义的行为(通常是硬错误),而不是替换失败。
在尝试访问其基础类型之前,您需要首先确定有问题的类型是枚举类型。按照typename std::enable_if<std::is_enum<H>::value, std::underlying_type<H>>::type::type
的思路写这篇文章。用这种可怕的混乱替换返回类型中的typename std::underlying_type<H>::type
,你会得到一个更可怕的混乱:)
如果你发现自己需要经常这样做——或者只是不想写typename std::enable_if<std::is_same<typename std::enable_if<std::is_enum<H>::value, std::underlying_type<H>>::type::type, uint8_t>::value>::type
——你可以写一个SFINAE友好的underlying_type
:
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 */> {};
以下是一个受T.C.解决方案启发的解决方案,适用于我的用例:
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;
};
示例用法:
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;
}
- 使用 [] 运算符时"binding reference of type discards qualifiers"
- 在 QVector<std::unique_ptr 上使用 std::find<Type>>
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 使用 cmake 的 Linux 终端上的"Conversion to non-scalar type is requested"错误
- 控制到达非空函数clang(-Wreturn-type)的末尾
- std::unordered_map 类型对象声明期间出现"field has incomplete type"错误
- 将系数存储在头文件的数组中("does not name a type"错误)
- 尝试打开 ifstream 时出现"Incomplete type"错误
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- 在"结构提升::enable_if<提升::is_pod<T>,无效>"中没有名为"type"的类型
- "Missing type specifier - int assumed"无法通过向主函数添加"return 0"来解决
- OpenCV CV_16F type
- C++ "错误:在'类 std::result_of< ... >"中没有名为'type'的类型"
- 将内存分配返回值强制转换为 TYPE 数组
- C++ 一个lambda浅拷贝const Type&如果它被赋予一个命名捕获,如[copy=val](){}?
- reference_wrapper导致"incomplete type is not allowed"
- 继承类时"invalid use of incomplete type ‘class tree_node_t’"
- 由于"error C4430: missing type specifier - int assumed. Note: C++ does not support default-int",我现在无法编
- 如何解决"'mutex' in namespace 'std' does not name a type"?
- C++11 枚举前向导致"underlying type mismatch"