【问题标题】:Is there any way for compile-time check of string user-defined literal?有没有办法对字符串用户定义的文字进行编译时检查?
【发布时间】:2016-08-06 09:03:40
【问题描述】:

我正在编写一个用户定义的string 文字来将月份名称转换为它们的数字。该文字的预期用法类似于

"Nov"_m

应该返回11

目前我的代码看起来像

constexpr Duration operator ""_m(const char* str, size_t len)
{
    return convert_month_to_int(str, len);
}

其中constexpr int convert_month_to_int(const char, size_t) 是一个进行实际转换的函数(如果月份名称不正确,则返回-1)。

问题是如果传递给这个文字的字符串没有命名任何月份,我想显示某种编译错误。我尝试通过以下方式使用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);
}

但这不起作用,因为编译器不确定convert_month_to_int(str, len) 将是一个常量表达式。

有没有办法实现这种行为?

【问题讨论】:

  • gcc 有扩展在这里使用模板方法。
  • @Jarod42 你的意思是可变参数模板用户定义的文字?它们不是仅用于整数和浮点类型吗?
  • 抱歉愚蠢(已删除的答案)等等,但实际上,只有一小部分有效月份标识符,为什么不将其设为enum?因为这就是enums 的用途。命名值,从中创建类型。
  • enum { Jan_m, Feb_m, ...漂亮!
  • 在我看来,您正在尝试使用参数创建一个函数,但使用 UDL 语法和operator+。你的例子可以写成make_date(2016, Aug, 6, 12, 50)。我认为你的方式有缺陷的原因是因为三月多少钱? 59还是60? 2016_y + "Aug"_m + "December"_m 是什么?似乎只有一种方法可以对您的表达式进行排序,并且您最好使用函数调用。

标签: c++ c++11 user-defined-literals


【解决方案1】:

我以不同的方式解决了这个问题,既不使用枚举也不使用字符串文字,即使不构造为 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.
}

我使用的方法是定义一个class type month,即documented to be a literal class type

然后我create constexpr instances of each month:

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 是一个宏,用于帮助那些在 C++11 中不完全存在的编译器 constexpr 支持跛行)

我也在一周中的几天使用相同的技术。

以上都是使用clang和-std=c++11编译的。它也适用于 gcc。 constexpr 位在 VS 中已损坏,但其他一切正常,包括在编译时检测错误的月份名称。

【讨论】:

    【解决方案2】:

    我同意改用枚举的建议。

    但无论如何,在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";
    }
    

    例如,另见this question

    【讨论】:

    • 不幸的是,只有将"NotAMonth"_m 的结果分配给constexpr 时才会产生编译时错误。
    • @alexeykuzmin0 - 即:只有在编译时检测到错误时才会产生编译时错误;我不知道在运行时检测到错误时施加编译时错误的方法
    • 不幸的是,我没有看到任何解决方案。问题是在您的运算符 "" 实现中,const char * strsize_t len 不是常量表达式。 (见,同样的问题,Columbo's answer)。所以我认为你不能在static_assert 条件下使用它们。除非您强制运算符在编译时运行,否则为时已​​晚,无法产生编译时错误。最简单的事情就是使用枚举。
    猜你喜欢
    • 2018-05-12
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 2023-03-13
    • 2021-01-04
    • 2013-09-22
    相关资源
    最近更新 更多