我想在编译时检查各种枚举是否包含给定值,因此我编写了以下内容:
#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不会更改错误。
答案 0 :(得分:3)
似乎该标准将这样的代码定义为格式错误,不需要诊断。看一下以下语句:
[可以在任何实例化之前检查模板的有效性。 [注:知道哪些名称是类型名称允许每个语法 以这种方式检查模板。 — [尾注]该程序是 格式错误,无需诊断,如果:
<...>
(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));
}
答案 1 :(得分:3)
在99/100的情况下,使用标签分发比使用模板专业化要好得多。
std::string filename("input.bmp");
bitmap_image image(filename);
人们通过在#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));
}
的名称空间中写一个from_int
扩展constexpr optional<the_enum_type> from_int_impl( tag_t<the_enum_type>, int )
(这样可以通过ADL找到它),或者为不可能的枚举(例如the_enum_type
名称空间中std
中的枚举。或from_int_details
的命名空间。
以下是此代码在MSVC 2017(编译器版本19.10)中进行编译。
答案 2 :(得分:0)
有问题的代码使用cl
v19.15.26726(Visual Studio版本15.9.0-pre.1.0)编译时没有警告或错误