Pao*_*o M 16 c++ enums sfinae overload-resolution variadic-templates
使用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);
}
Run Code Online (Sandbox Code Playgroud)
我希望foo根据类型递归调用正确的重载H:
std::begin(h)为某个h类型定义H,我希望选择重载号1H是"整数类型",我想要重载2号.这样可以正常工作.但是如果我为枚举类型添加另一个重载(你可以尝试取消注释第三个重载),那么我得到:
错误:只有枚举类型具有基础类型
我同意只有enums有一个底层类型,因此为什么不是第三次重载(with std::underlying_type)得到SFINAE-d了?
T.C*_*.C. 20
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 */> {};
Run Code Online (Sandbox Code Playgroud)