为返回 void 的函数声明 constexpr 的任何理由



这是我读到的:对静态成员函数使用别名?

在答案中,我看到了使用constexpr的建议.将constexpr用于void函数的原因是什么?

请演示一个简单的用例。我是constexpr新手,所以在复杂的例子中,我不会理解要点。

Rahul的回答引用了允许void constexpr函数的标准段落,但它没有给出用例。我想到的一个用例是有一个constexpr类,并像往常一样分解出帮助程序方法中方法的常见行为。该标准明确提到了执行检查的函数,例如断言。我手头没有具体的例子,但我可以想象类似

class A
{
public:
    constexpr X doSomething(Y arg1) {
        checkInvariant();
        constraintOnYArgument(arg1);
        // ...
        checkInvariant();        
    }
    constexpr X doSomethingElse(Y arg1) {
        checkInvariant();
        constraintOnYArgument(arg1);
        // ...
        checkInvariant();        
    }
private:
    constexpr void constraintOnYArguments(Y arg) {
    }
    constexpr void checkInvariant() {
        // some checks
        if (!some condition) {
            throw std::logic_error("Oh no!");
        }
    }
};

根据 C++ 14 标准,void 是一种文字类型

如果类型是以下类型,则类型为文本类型:

— 无效;或

— 标量类型;或

— 引用类型;或

— 文字类型的数组;或

具有以下所有属性的类类型(条款 9(: — 它有一个微不足道的析构函数,

— 它是一个聚合类型 (8.5.1( 或至少有一个 constexpr 不是副本或移动的构造函数或构造函数模板 构造函数,以及

— 它的所有非静态数据成员和基类都是 非易失性文本类型。

从这里:

允许

使用任意表达式语句,以便允许 调用执行检查的函数并允许类似断言 构建。void 也变成了文字类型,因此 constexpr 仅用于执行此类检查的函数可能返回 void。

一个合理的用例是操作易失性变量。以下是使用GNU工具(g++,ld(进行嵌入式编程的一个非常简单的情况:

要使外围设备的地址成为constexpr,您需要将其放在固定位置。这必须在链接器脚本中完成:

⋮
/* Define output sections */
SECTIONS
{
GPIO    0x48000000 (NOLOAD) : { *(.GPIO) }
⋮

现在,.GPIO部分位于固定地址0x48000400。外设可以通过包含易挥发性成员的 POD 进行建模。在以下示例中,POD 名为 gpio_t,并且只有一个成员:mode 。可以在constexpr函数中设置成员。当然,使用函数将变量设置为常量值没有任何好处。但在实际用例中,必须计算值和地址。例如,考虑为波特率设置一个分频器。

struct gpio_t {
    volatile std::uint32_t mode;
   };
__attribute__ ((section (".GPIO"))) gpio_t Gpio = {0};
static constexpr gpio_t *port {&Gpio};
static constexpr void init () {
    port->mode = 42u;
   };
void main {
    init ();
    ⋮
};

注意:将整数强制转换为地址的 C 样式习惯用法不起作用,因为它reinterpret_cast<>不符合创建constexpr指针的条件(请参阅 自 C++14 非法(。以下操作失败

constexpr gpio_t *port {(gpio_t *) 0x48000400};

只要参数号是整数常数,此 constexpr 版本将在编译时计算结果(仅限 C++11 个编译器(。当数字是运行时整数时,相同的函数完全能够在运行时计算结果。因此,您不需要同一程序的两个不同版本:一个用于编译时,另一个用于运行时。一个实现可以完成所有操作。

相关内容

最新更新