【问题标题】:Does the default argument for a function parameter is considered as an initializer for that parameter?函数参数的默认参数是否被视为该参数的初始值设定项?
【发布时间】:2022-09-24 22:23:29
【问题描述】:

假设我有这样的函数声明:

static const int R = 0;
static const int I = 0;

void f(const int& r = R);
void g(int i = I);

根据 [dcl.fct.default]/1:

如果在参数声明中指定了初始化子句,则 初始化子句用作默认参数 [..]

并且根据语法结构,一个初始化器可以包括一个初始化子句.正确的?

所以我得出结论,R初始化器对于参数rI 也是初始化器对于参数i

现在根据 [const.expr]/2:

变量或临时对象o 是常量初始化的,如果

  • (2.1) 要么它有初始化器[..] 和
  • (2.2) 其初始化的完整表达式是一个常量表达式 [..]

所以这两个参数都有一个初始化器,而且它们初始化的完整表达式是一个常量表达式。

那么,是否考虑了 ri 两个参数常量初始化?

  • g() 等价于g(I) 等价于g(0)
  • @Jarod42 - 你想说什么?
  • 不知道你的问题是什么......函数参数永远不是constexpr,并且存在上述等价性。

标签: c++ language-lawyer initializer default-arguments


【解决方案1】:

不,因为一个初始化子句不一定是初始化器.这里有问题的语法项目是这个版本的parameter-declaration

属性说明符序列选择这个选择decl-specifier-seq 声明符 = 初始化子句

使用适量的分毛,这意味着形式带有默认参数的参数声明类似于初始化,但仍有细微的不同。最明显的区别是,如果使用实际参数,则会忽略默认参数。不太明显的是,一个参数实际上不能被常量初始化,即使它的默认参数是一个常量表达式。即使仅在编译时评估函数,这仍然是正确的。下面是一些代码,显示了含义上的细微差别:

#include <random>

// R may be evaluated at compile time and must be constant-initialized
static constexpr int R = 0;

// f may be evaluated at compile time
constexpr int f(const int& r = R) { return r + 42; }

// I must be constant- *or* zero-initialized, even if only evaluated at runtime
constinit const int I = f();

// g is an "immediate function": it may not be evaluated at runtime
consteval int g(int i = I) { return i - 42; }

int main() {
    // A variable that may not appear in constant expressions,
    // because it is not constant-initialized
    const int not_const = std::rand();

    int x1 = f();                       // OK, constant initialization
    int x2 = f(not_const);              // OK, evaluated at runtime
    constexpr int x3 = f();             // OK
    // constexpr int x4 = f(not_const); // error, must be constant-initialized

    int y1 = g();                       // OK
    // int y2 = g(not_const);           // error
    constexpr int y3 = g();             // OK
    // constexpr int y4 = g(not_const); // error
}

正如您所看到的here,这只会生成一个对f(int const&amp;) 的运行时调用,而不会对g(int) 生成一个运行时调用。即使其他调用的参数实际上是编译时常量,您也不能这样使用或指定它们:

constexpr int f(const int& r = R) {
    // constexpr int x = r; // error, not a constant expression
    return r + 42;
}

consteval int g(int i = I) {
    // constexpr int y = i; // still not a constant expression!
    return i - 42; 
}

// Also not allowed:
// consteval void h(constexpr int x = 0, constinit int y = 1); 

【讨论】:

    猜你喜欢
    • 2017-11-19
    • 2010-10-28
    • 2011-08-26
    • 2011-02-20
    • 2011-04-09
    • 2019-09-11
    • 1970-01-01
    相关资源
    最近更新 更多