C++17:使用 std::optional 来评估枚举是否包含值
C++17: using std::optional to evaluate if enum contains value
我想在编译时检查各种枚举是否包含给定值,所以我写了以下内容:
#include <optional>
enum class test_enum : int {
VALUE_0 = 0,
VALUE_1 = 1
};
// Template function to perform check
template<typename T>
constexpr std::optional<T> from_int(int value)
{
static_assert(false, __FUNCTION__ " not implemented for this type; see build output");
return std::optional<T>();
}
// Specialization for test_enum
template<>
constexpr std::optional<test_enum> from_int(int value)
{
switch (value) {
case static_cast<int>(test_enum::VALUE_0) :
return test_enum::VALUE_0;
case static_cast<int>(test_enum::VALUE_1):
return test_enum::VALUE_1;
default:
return std::optional<test_enum>();
}
}
int main(int argc, char* argv[])
{
static_assert(from_int<test_enum>(1));
return 0;
}
使用 Visual Studio 2017(版本 15.8.6(,代码成功编译,输出中没有错误。但是,错误窗口显示
E0028: expression must have a constant value" at line 30. (the first line of main)
和
"std::_Optional_construct_base<test_enum>::_Optional_construct_base(std::in_place_t, _Types &&..._Args) [with _Types=<test_enum>]" (declared implicitly) is not defined)".
关于为什么会这样的任何提示?我可以忽略 E0028,但如果可能的话,我宁愿不要。
编辑:从from_int中删除static_assert不会更改错误。
标准似乎将这样的代码定义为格式不正确,无需诊断。请看以下语句:
[可以在任何实例化之前检查模板的有效性。 [注意:知道哪些名称是类型名称允许每个语法 要以这种方式检查的模板。— 尾注 ] 程序是 格式不正确,无需诊断,如果出现以下情况:
<...>
(8.4( 假设 紧跟在其定义之后的模板实例化将 由于构造不依赖于模板而导致格式错误 参数...] 1
要使其格式正确,请勿使用static_assert(false)
。相反,请使用以下技巧(使用 GCC 7 和 CLang 7 编译(:
#include <optional>
enum class test_enum : int {
VALUE_0 = 0,
VALUE_1 = 1
};
template<typename T>
constexpr bool false_t = false;
// Template function to perform check
template<typename T>
constexpr std::optional<T> from_int(int value)
{
static_assert(false_t<T>, "Not implemented for this type; see build output");
return std::optional<T>();
}
// Specialization for test_enum
template<>
constexpr std::optional<test_enum> from_int<test_enum>(int value)
{
switch (value) {
case static_cast<int>(test_enum::VALUE_0) :
return test_enum::VALUE_0;
case static_cast<int>(test_enum::VALUE_1):
return test_enum::VALUE_1;
default:
return std::optional<test_enum>();
}
}
int main()
{
static_assert(from_int<test_enum>(1));
}
在 99/100 的情况下,使用标签调度比使用模板专用化要好得多。
#include <optional>
enum class test_enum : int {
VALUE_0 = 0,
VALUE_1 = 1
};
template<class T> struct tag_t {};
namespace from_int_details {
template<class T>
std::optional<T> from_int_impl( tag_t<T>, int value ) = delete;
}
template<class T>
std::optional<T> from_int( int value ) {
using namespace from_int_details;
return from_int_impl( tag_t<T>{}, value );
}
// Overload for test_enum, same namespace as test_enum *or* in from_int_details:
constexpr std::optional<test_enum> from_int_impl(tag_t<test_enum>, int value)
{
switch (value) {
case static_cast<int>(test_enum::VALUE_0) :
return test_enum::VALUE_0;
case static_cast<int>(test_enum::VALUE_1):
return test_enum::VALUE_1;
default:
return std::optional<test_enum>();
}
}
int main()
{
static_assert(from_int<test_enum>(1));
}
在这里,人们通过在the_enum_type
命名空间中编写constexpr optional<the_enum_type> from_int_impl( tag_t<the_enum_type>, int )
来扩展from_int
(因此可以通过 ADL 找到(,或者在from_int_details
命名空间中为不可能这样做的枚举(如std
中的枚举(编写。 或者tag_t
的命名空间。
下面是在 MSVC 2017 编译器版本 19.10 中编译的此代码。
有问题的代码使用cl
v19.15.26726(Visual Studio 版本 15.9.0-pre.1.0(编译时没有警告或错误
- 是否有 Windows 用户空间函数来枚举连接的网络共享?
- C++17:使用 std::optional 来评估枚举是否包含值
- 使用枚举为数组编制索引是否安全?
- 是否可以在C++变量中保存多种类型的枚举?
- 是否可以确定枚举是否为强类型?
- 是否可以使用泛型枚举类型作为函数的参数?
- 是否可以基于私有/受保护成员分配类枚举?
- 如何检查类中定义的枚举类型变量是否被分配给?
- 表达式中使用的枚举器是否与其枚举的基础类型具有相同的类型?
- 是否巢枚举课
- 将指向类型化/大小的枚举的指针转换为指向基础类型的指针是否安全?
- 是否可以使用 static_cast 从可变参数枚举创建 boost::mpl::list_c
- 枚举是否可以在C++中减小到其位大小
- C++枚举是否可以大于 64 位?
- 新的类型安全枚举是否定义为从 0 开始
- 虚拟方法返回代表派生对象类型的枚举 - 是否可以(在设计方面)
- POD 类中的嵌套枚举是否使它不是 POD
- 无作用域枚举是否仍然有用
- 此枚举是否有效,如果有效,为什么
- 枚举是否应该从dll中导出