非静态成员作为非静态成员函数的默认参数

Arm*_*yan 28 c++ member-functions default-value

struct X
{
   X():mem(42){}
   void f(int param = mem) //ERROR
   {
      //do something
   }
private: 
   int mem;
};
Run Code Online (Sandbox Code Playgroud)

任何人都可以给我一个原因,为什么这在C++中是非法的?!也就是说,我知道这是一个错误,我知道错误意味着什么,我只是无法理解为什么这是非法的!

Naw*_*waz 41

你的代码(简化):

struct X
{
   int mem;
   void f(int param = mem); //ERROR
};
Run Code Online (Sandbox Code Playgroud)

您希望将非静态成员数据用作成员函数的参数的默认值.想到的第一个问题是:默认值属于哪个类的特定实例mem

X x1 = {100};  //mem = 100
X x2 = {200};  //mem = 200

x1.f(); //param is 100 or 200? or something else?
Run Code Online (Sandbox Code Playgroud)

你的答案可能是100因为f()在对象上调用x1 它有mem = 100.如果是这样,那么它需要实现f()如下:

void f(X* this, int param = this->mem);
Run Code Online (Sandbox Code Playgroud)

这反过来要求在初始化其他参数之前首先初始化第一个参数.但是C++标准没有指定函数参数的任何初始化顺序.因此,这是不允许的.其原因与C++标准不允许这样的原因相同:

int f(int a, int b = a); //§8.3.6/9
Run Code Online (Sandbox Code Playgroud)

事实上,§8.3.6/ 9明确地说,

每次调用函数时都会计算默认参数.函数参数的评估顺序未指定.因此,函数的参数不应在默认参数表达式中使用,即使它们未被计算.

本节的其余部分是一个有趣的阅读.


一个与"默认"参数相关的有趣主题(尽管与此主题无关​​):


Pup*_*ppy 6

必须在编译时知道默认参数.当你谈到像函数调用这样的东西时,那么函数在编译时是已知的,即使返回值不是,所以编译器可以生成该代码,但是当你默认为成员变量时,编译器不会知道在编译时在哪里找到该实例,这意味着它实际上必须通过参数(this)来查找mem.请注意,你不能做类似的事情void func(int i, int f = g(i));,两者实际上是相同的限制.

我也认为这种限制很愚蠢.但是,C++充满了愚蠢的限制.

  • -1表示`"默认参数必须在编译时知道".这不是真的. (3认同)

use*_*672 5

正如DeadMG上面提到的,有点像

void func(int i, int f = g(i))

出于同样的原因是非法的.但是,我认为这不仅仅是一个愚蠢的限制.为了允许这样的构造,我们需要限制函数参数的评估顺序(因为我们需要在this-> mem之前计算它),但是c ++标准明确地拒绝了对评估顺序的任何假设.