我们如何处理用户定义文字输入中的错误?

How do we handle errors in the input of a User Defined Literal?

假设我想要这样定义整数百分比:

constexpr int operator""_percent (char const * literal)
{
    int percent(0);
    for(; *literal != '[=10=]'; ++literal)
    {
        if(*literal >= '0' && *literal <= '9')
        {
            percent *= 10;
            percent += *literal - '0';
            if(percent > 100)
            {
                ...what do we do here?...
            }
        }
        else
        {
            ...what do we do here?...
        }
    }
    return percent;
}

我正在考虑抛出,但我记得 constexprthrow 不匹配(或者只在 C++14 和更早版本中?)。在这种情况下惯例是什么?在 User Defined Literal 运算符中报告错误的正确方法是什么?

注意:我目前使用的是 C++17,但计划很快切换到 C++20。

我真的不知道这种情况的常见做法是什么,但我会在下面给出一些想法。


使用 C++20,您可以使用文字运算符 consteval 而不是 constexpr.

如果出错,您可以抛出异常。 throw 表达式本身在 constexpr/consteval 函数中是允许的,但实际上抛出使其不是常量子表达式。由于 consteval 函数调用必须是常量表达式,因此程序将 ill-formed 出错并且编译器必须对其进行诊断。


对于 C++17,您仍然可以抛出异常,但 consteval 不可用。

对于有效文字,这不是问题。只要不计算 throw 表达式,对文字运算符的调用仍然可以是常量子表达式。

但是,如果字面值无效,并且未在需要常量表达式的上下文中使用,您通常不会得到 compile-time 诊断。

取而代之的是,在计算文字时,您会在程序执行期间抛出异常。这可能是不可取的,例如,如果应该在 noexcept 函数中使用文字。

或者您也可以使用 assert 而不是抛出异常。自 C++17 起,如果参数的计算结果为 true.

,则保证它是常量子表达式

如果断言失败,您也不会收到 compile-time 错误,相反,程序将在计算文字时中止。

使用 NDEBUG 宏可以在发布版本中删除断言。这不会影响异常规范,但您仍然需要决定如何处理发布版本中未在调试版本测试中捕获的错误。这对您的使用来说可能不够安全。

我认为通常没有任何 C++17 方法可以强制出现 compile-time 错误。


正如我在问题的评论中提到的,我对我的建议 correct/good 表示怀疑。请也阅读它们。