I'm writing a user-defined string
literal to convert names of months into their numbers. The expected usage of this literal is something like
我正在编写一个用户定义的字符串文字,将月名转换为数字。这个文字的预期用法是这样的
"Nov"_m
which should return 11
.
它应该返回11。
At the moment my code looks like
目前我的代码看起来是这样的
constexpr Duration operator ""_m(const char* str, size_t len)
{
return convert_month_to_int(str, len);
}
where constexpr int convert_month_to_int(const char, size_t)
is a function which does the actual conversion (or returns -1
if the month name is incorrect).
其中constexpr int convert_month_to_int(const char, size_t)是执行实际转换的函数(如果月名不正确,则返回-1)。
The problem is that I would like to show some kind of compile error if the string passed to this literal does not name any month. I tried using static_assert
in the following way:
问题是,如果传递给这个文本的字符串没有任何月份的名称,那么我希望显示一些编译错误。我尝试使用static_assert,方法如下:
constexpr Duration operator ""_m(const char* str, size_t len)
{
static_assert(convert_month_to_int(str, len) > 0, "Error");
return convert_month_to_int(str, len);
}
but this does not work since the compiler is not sure that convert_month_to_int(str, len)
will be a constant expression.
但是这并不起作用,因为编译器不确定convert_month_to_int(str, len)是否是常量表达式。
Is there any way of achieving this behavior?
有什么方法可以达到这种行为吗?
2 个解决方案
#1
2
I've approached this problem in a different way, using neither enums nor string literals, and bad month names are detected even when not constructed as constexpr
:
我以另一种方式来处理这个问题,既不使用枚举也不使用字符串文字,即使不是构造为constexpr,也会检测到糟糕的月份名称:
#include "date.h"
int
main()
{
using namespace date::literals;
auto m1 = nov; // ok
static_assert(unsigned{nov} == 11, ""); // ok
auto m2 = not_a_month;
test.cpp:86:15: error: use of undeclared identifier 'not_a_month'
auto m2 = not_a_month;
^
1 error generated.
}
The approach I used is to define a class type month
which is documented to be a literal class type.
我使用的方法是定义一个类类型月,它被文档化为一个文字类类型。
I then create constexpr
instances of each month:
然后我创建每个月的constexpr实例:
CONSTDATA date::month jan{1};
CONSTDATA date::month feb{2};
CONSTDATA date::month mar{3};
CONSTDATA date::month apr{4};
CONSTDATA date::month may{5};
CONSTDATA date::month jun{6};
CONSTDATA date::month jul{7};
CONSTDATA date::month aug{8};
CONSTDATA date::month sep{9};
CONSTDATA date::month oct{10};
CONSTDATA date::month nov{11};
CONSTDATA date::month dec{12};
(CONSTDATA
is a macro to help compilers which aren't quite there with C++11 constexpr
support limp along)
(CONSTDATA是一个用于帮助编译器的宏,而在c++ 11 constexpr支持下,编译器还不完善)
I also used the same technique for days of the week.
我也在一周的几天里使用了同样的技术。
The above was all compiled using clang with -std=c++11
. It will also work with gcc. The constexpr
bits are broken in VS, but everything else works, including detecting bad month names at compile time.
以上都是使用-std=c++11的clang编译的。它还将与gcc合作。constexpr位在VS中被破坏,但是其他的一切都可以工作,包括在编译时检测坏的月份名称。
#2
3
I agree with suggestion to use an enum instead.
我同意使用enum的建议。
But anyways, the usual way to signal an error like this in a constexpr
function is to throw an exception.
但是不管怎样,在constexpr函数中发出这样一个错误信号的通常方法是抛出一个异常。
constexpr Duration operator ""_m(const char* str, size_t len)
{
return convert_month_to_int(str, len) > 0 ? convert_month_to_int(str, len) : throw "Error";
}
See also this question for instance.
例如,请参见这个问题。
#1
2
I've approached this problem in a different way, using neither enums nor string literals, and bad month names are detected even when not constructed as constexpr
:
我以另一种方式来处理这个问题,既不使用枚举也不使用字符串文字,即使不是构造为constexpr,也会检测到糟糕的月份名称:
#include "date.h"
int
main()
{
using namespace date::literals;
auto m1 = nov; // ok
static_assert(unsigned{nov} == 11, ""); // ok
auto m2 = not_a_month;
test.cpp:86:15: error: use of undeclared identifier 'not_a_month'
auto m2 = not_a_month;
^
1 error generated.
}
The approach I used is to define a class type month
which is documented to be a literal class type.
我使用的方法是定义一个类类型月,它被文档化为一个文字类类型。
I then create constexpr
instances of each month:
然后我创建每个月的constexpr实例:
CONSTDATA date::month jan{1};
CONSTDATA date::month feb{2};
CONSTDATA date::month mar{3};
CONSTDATA date::month apr{4};
CONSTDATA date::month may{5};
CONSTDATA date::month jun{6};
CONSTDATA date::month jul{7};
CONSTDATA date::month aug{8};
CONSTDATA date::month sep{9};
CONSTDATA date::month oct{10};
CONSTDATA date::month nov{11};
CONSTDATA date::month dec{12};
(CONSTDATA
is a macro to help compilers which aren't quite there with C++11 constexpr
support limp along)
(CONSTDATA是一个用于帮助编译器的宏,而在c++ 11 constexpr支持下,编译器还不完善)
I also used the same technique for days of the week.
我也在一周的几天里使用了同样的技术。
The above was all compiled using clang with -std=c++11
. It will also work with gcc. The constexpr
bits are broken in VS, but everything else works, including detecting bad month names at compile time.
以上都是使用-std=c++11的clang编译的。它还将与gcc合作。constexpr位在VS中被破坏,但是其他的一切都可以工作,包括在编译时检测坏的月份名称。
#2
3
I agree with suggestion to use an enum instead.
我同意使用enum的建议。
But anyways, the usual way to signal an error like this in a constexpr
function is to throw an exception.
但是不管怎样,在constexpr函数中发出这样一个错误信号的通常方法是抛出一个异常。
constexpr Duration operator ""_m(const char* str, size_t len)
{
return convert_month_to_int(str, len) > 0 ? convert_month_to_int(str, len) : throw "Error";
}
See also this question for instance.
例如,请参见这个问题。