如何处理用户自定义字面量输入中的错误?

3

假设我想定义一个百分比整数,如下所示:

constexpr int operator""_percent (char const * literal)
{
    int percent(0);
    for(; *literal != '\0'; ++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;
}

我曾考虑使用throw,但我记得constexprthrow不太匹配(或者这只是在C++14及更早版本中如此?)。在这种情况下的惯例是什么?如何在用户定义字面量运算符中报告错误?
注:我目前使用的是C++17,但计划很快转换到C++20。

1
std::strtol 不是一个 constexpr 函数,因此你的整个字面量运算符无法成为 constexpr。 - 273K
1
这是关于C++20还是之前的版本?在C++20中,我建议将其设置为consteval而不是constexpr,然后抛出异常将保证导致编译时错误。 - user17732522
@user17732522:这只是 <chrono> 的设计者 Howard Hinnant 的个人偏好。 - Davis Herring
@DavisHerring 我可以理解为什么将其设置为 noexcept 如果它不是 consteval 会有优势,但是我没有看到在不让其具有错误报告的情况下不将其设置为 consteval 的任何优点,除非是为了允许使用运行时值直接调用运算符,这对我来说似乎不是预期的用法。但正如我所说,我可能忽略了某些东西。 - user17732522
@user17732522:即使在noexcept函数中,您也可以使用throw来失败常量评估。我认为错误处理策略只是为了与运行时设施保持一致。 - Davis Herring
显示剩余6条评论
1个回答

2

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


使用C++20,您可以将字面值运算符constexpr替换为consteval

发生错误时,您可以抛出异常。 throw表达式本身允许在constexpr/consteval函数中使用,但实际抛出异常会使其不成为常量子表达式。由于consteval函数调用必须是常量表达式,因此程序在发生错误时将无效,并且编译器必须诊断它。


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

对于有效的文字,这是没有问题的。只要不评估throw表达式,对文字操作符的调用仍然可以是常量子表达式。

如果文字是无效的,则通常不会在需要常量表达式的上下文中获得编译时诊断。

相反,在评估文字时将抛出异常。这可能是不希望发生的,例如,如果文字应该在noexcept函数中使用。

或者,您还可以使用assert而不是抛出异常。自C++17以来,如果参数计算结果为true,则保证它是常量子表达式。

如果断言失败,则您也不会得到编译时错误,相反,在评估文字时程序将中止。

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

我认为没有任何C++17的方法可以通用地强制进行编译时错误。


正如我在问题的评论中提到的,我对我的建议是否正确/好有些怀疑。因此,请也阅读它们。


看到chrono的日操作符,这真的很可怕...如果你传递一个无效的数字,它甚至可能使用一些“随机”的数字(可能是d&255),这意味着你不能确定事情是否会按照你的期望进行,我认为这相当糟糕。 - Alexis Wilke
这并不可怕。5000dday{5000} 具有完全相同的行为。它们都可以编译并提供未指定的结果。有很多工具可以观察和测试结果。 - Howard Hinnant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接