有没有办法在编译时检查字符串用户定义的文字?

时间:2022-08-29 01:54:55

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.

例如,请参见这个问题。