如何使用SFINAE为枚举类中缺少的值进行polyfill
How to use SFINAE to make a polyfill for missing values in enum class?
我觉得这应该很容易,但我已经为此挣扎了一段时间,所以我想我应该在这里问。
我想制作一个模板元函数,它以一个与C++11枚举类对应的类型作为参数,并返回一个int:
- 如果枚举类
E
具有枚举器值a
,则返回static_cast<int>(E::a)
- 如果枚举类
E
没有枚举器值a
,则返回42
然后,我想制作一个模板函数,它接受某个枚举类E
的运行时实例,将其静态强制转换为int,并检查它是否与此元函数匹配。
我尝试了的多次迭代,模板化结构并使用模板部分专门化来区分E::a
是否存在,还使用函数模板。。。我不确定我是否能重建我尝试过的一切,但这是最新的迭代:
template <typename E>
inline int get_a_int_val(int result = E::a) { return result; }
template <typename E>
inline int get_a_int_val(int result = 42) { return result; }
template <typename E>
inline bool is_a_val(const E & input) {
return static_cast<int>(input) == get_a_int_val<E>();
}
这不起作用,因为我正在重新定义默认参数。
template <typename E, int result = E::a>
inline int get_a_int_val() { return result; }
template <typename E, int result = 42>
inline int get_a_int_val() { return result; }
template <typename E>
inline bool is_a_val(const E & input) {
return static_cast<int>(input) == get_a_int_val<E>();
}
这不起作用,因为非类型参数不能依赖于类型参数。
template <typename E>
struct get_a_int_val {
static const int value = 42;
};
template <typename E>
struct get_a_int_val<E> {
static const int value = static_cast<int>(E::a);
};
template <typename E>
inline bool is_a_val(const E & input) {
return static_cast<int>(input) == get_a_int_val<E>::value;
}
这不起作用,因为
error:
class template partial specialization does not specialize any template
argument; to define the primary template, remove the template argument
list
正确的方法是什么?
动机:
我想这样做的原因是,我想解决libstdc++中的一个bug,我在这里报告了这个bug:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68307
在C++11中,<system_error>
标头中有一组std::errc
的枚举器值,这些值本应定义,但在mingw中,其中一些值丢失了。这会在我的程序中导致编译错误,因为根据Asio
的配置方式,lib::asio::errc
可能被类型定义为std::errc
,而websocketpp
假设lib::asio::errc::operation_canceled
是一个定义的符号。我想把某种垫片放在websocketpp
代码中,这样它就可以在任何平台上被定义为可接受的(如果存在,则定义为lib::asio::errc::operation_canceled
,如果不存在,则从<cerrno>
定义为ECANCELED)
您可以通过多种方式做到这一点,其中之一如下:
template <typename E, typename Enable = void>
struct get_a_int_val {
static const int value = 42;
};
template <typename E>
struct get_a_int_val<E, typename std::enable_if<std::is_same<decltype(E::a),
decltype(E::a)>::value, void>::type>{
static const int value = static_cast<int>(E::a);
};
现场演示
您可以为此创建一个特征:
template <typename E>
std::false_type has_a_impl(...);
template <typename E> auto has_a_impl(int) -> decltype(E::a, std::true_type{});
template <typename E>
using has_a = decltype(has_a_impl<E>(0));
然后在SFINAE:中使用
template <typename E>
std::enable_if_t<has_a<E>::value, int>
get_a_int_val() { return static_cast<int>(E::a); }
template <typename E>
std::enable_if_t<!has_a<E>::value, int>
get_a_int_val() { return 42; }
演示
- 为什么使用SFINAE而不是函数重载
- 如何使用模板函数的函数签名进行SFINAE
- 数据成员SFINAE的C++17测试:gcc vs clang
- 使用在用于SFINAE的void_t中具有参数的方法
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 提供与TMP和SFINAE的通用接口
- "Inverse SFINAE"避免模棱两可的过载
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 如何在儿童类中使用SFINAE
- 使用 SFINAE 作为模板参数的编译时递归
- 使用 SFINAE 设计模板方法
- 与SFINAE支票交朋友
- C++许多 SFINAE 风格的过载
- 是否可以混合使用SFINAE和模板专业化?
- C++表达SFINAE和ostream操纵器
- SFINAE不能防止模棱两可的操作员过载吗?
- SFINAE是否取决于类型推断?
- MSVC 无法编译 SFINAE 检查
- SFINAE 检查模板参数运算符
- 如何使用SFINAE为枚举类中缺少的值进行polyfill