【问题标题】:Will consteval allow using static_assert on function arguments?consteval 是否允许在函数参数上使用 static_assert?
【发布时间】:2019-12-05 04:44:33
【问题描述】:

目前您不能使用static_assert 来验证constexpr 函数的参数,即使对它的所有调用确实是constexpr。 这是有道理的,因为编译器仍然必须创建此函数的非常量实例化,以防其他模块尝试调用它。 遗憾的是,即使函数是 static 或在匿名命名空间中也是如此。

然而,C++20 将引入一个新关键字 consteval,它类似于 constexpr,但它不允许以非 constexpr 方式调用函数。在这种情况下,编译器可以确定函数参数在编译时总是已知的。因此,理论上应该可以使用static_assert 验证它们。

问题是:标准允许吗?


例子:

#include <iostream>

consteval char operator""_bchar(const char text[], const size_t length)
{
    static_assert(length == 8, "Binary char has to have 8 digits!"); // <-- This is currently not possible.
    uint8_t byte = 0;
    for (size_t i = 0; i != length; ++i)
    {
        byte <<= 1;
        byte |= text[i] == '1' ? 0b00000001 : 0b00000000;
    }
    return byte;
}

int main()
{
    std::cout << "01000001"_bchar << std::endl;
    return 0;
}

我问是因为我要编写一些用户定义的文字(比示例更复杂)。我可以选择使用编译器扩展来处理验证,或者等待编译器更新并编写完全符合标准的代码。

【问题讨论】:

    标签: c++ static-assert c++20 consteval


    【解决方案1】:

    consteval 是否允许在函数参数上使用 static_assert?

    没有。函数参数从来没有并且将继续不能用作常量表达式。

    常量求值和可用作常量表达式之间是有区别的。 consteval 确保我们处于常量评估上下文中,但它也不会导致所有内容都变为常量表达式。

    为了让函数参数可用作常量表达式,您需要将所有内容都隐式地设为模板:

    template <int> struct X { };
    
    consteval auto foo(int i) {
        static_assert(i > 10); // in order to allow this...
        return X<i>{};         // ... you'd have to allow this too
    }
    

    现在foo(20)foo(30) 返回不同的类型。这是一个模板。


    在 Andrew Sutton 的Translation and evaluation: A mental model for compile-time metaprogramming 中可以找到了解为什么这是一个基本和固有限制的重要背景阅读:

    拥有一个编译时评估的心智模型,将其与 翻译对我很有帮助。特别是,它帮助我理解了什么不是 可能(例如,在评估期间实例化模板)。这有助于修剪设计空间 否则大而复杂的语言特征。希望其他人也会发现此说明对您有所帮助。


    虽然特别是 static_assert,但您可以添加一个解决方法来导致编译失败。这只是添加了在持续评估期间根本无法使用的任何内容。喜欢:

    #define CONSTEVAL_STATIC_ASSERT(c, msg) do { if (!(c)) throw msg; } while(false)
    

    如:

    consteval char operator""_bchar(const char text[], const size_t length)
    {
        CONSTEVAL_STATIC_ASSERT(length == 8, "Binary char has to have 8 digits!");
        // ...
    }
    

    【讨论】:

    • 您的 CONSTEVAL_STATIC_ASSERT 在编译时不会失败。它在运行时抛出异常。我使用g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
    • 没关系,如果我尝试将它分配给 constexpr 常量,它会起作用。
    • There is a difference between something being constant evaluated and being usable as a constant-expression.有什么区别?
    • @NO_NAME 已经是X&lt;i&gt; 这就是问题所在。是的,允许前者必然意味着允许后者。
    • 嗯,我想 consteval 函数已经需要在调用时显示它们的代码。那么隐式地制作模板有什么问题呢?
    猜你喜欢
    • 2020-04-20
    • 2021-10-26
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 2021-09-22
    • 1970-01-01
    相关资源
    最近更新 更多