【问题标题】:Why are these default arguments allowed?为什么允许使用这些默认参数?
【发布时间】:2014-11-19 13:37:25
【问题描述】:

我找到了this 的问题,我完全感到困惑。

答案说b 无效,“非静态成员不能用作默认参数。”。这很有道理。

我不明白为什么其他两个都可以。事实上,如果默认值不是常量表达式,我很难理解语义是什么......

这里发生了什么?默认参数在编译时明确评估。编译器是否只是选择当前值?

#include <iostream>

int g_x = 44; 

struct Foo 
{ 
  int m_x; 
  static int s_x; 

  Foo(int x) : m_x(x) {} 
  int a(int x = g_x) { return x + 1; } 
  int b(int x = m_x) { return x + 1; }
  int c(int x = s_x) { return x + 1; }
}; 

int Foo::s_x = 22; 

int main(int argc, char** argv) 
{ 
  Foo f(6); 

  std::cout << f.a() << std::endl; 
  std::cout << f.b() << std::endl; 
  std::cout << f.c() << std::endl; 

  return 0; 
}

【问题讨论】:

  • “默认参数在编译时明确评估” - 不,它们不是。每次调用函数时都会对它们进行评估。
  • @MikeSeymour:看起来像答案,闻起来像答案......
  • 我不知道非静态成员不能用作默认参数。我不知道为什么不允许这样做。
  • @PhilH:这是一个答案的片段。现在有一个正确的答案。
  • @NeilKirk:出于同样的原因,不能使用其他参数(this 是参数的特例)。未指定评估顺序,但需要解决参数评估之间的依赖关系。

标签: c++ default-arguments


【解决方案1】:

实际上,在调用函数时会评估默认参数,这就是为什么这样做是可以的。从draft C++ standard 部分8.3.6 默认参数 说(强调我的前进):

每次调用函数时都会评估默认参数。未指定函数参数的评估顺序。 因此,函数的参数不应在默认情况下使用 论点,即使它们没有被评估。函数的参数 在默认参数之前声明在范围内并且可以隐藏命名空间 和类成员名称。

来自同一部分的以下示例为我们提供了为什么我们可以使用静态成员但不能使用非静态成员的理由:

[ 示例:以下示例中 X::mem1() 的声明为 格式错误,因为没有为非静态成员提供对象 X::a 用作初始化器。

int b;
class X {
    int a;
    int mem1(int i = a); // error: non-static member a
                         // used as default argument
    int mem2(int i = b); // OK; use X::b
    static int b;
};

X::mem2() 的声明是有意义的,但是,因为没有对象 需要访问静态成员 X::b。 类、对象和 成员在第 9 条中描述。-结束示例]

【讨论】:

  • 我不明白该示例如何解释为什么不能将非静态成员用作默认参数。拥有非静态成员a 的潜在问题是什么,例如同一类的两个对象x,比如x1x2,每个对象都有自己的值a,比如@987654329 @ 和x2.a=3,将其用作mem1 的默认参数,例如在x1.mem1()x2.mem1()?
【解决方案2】:

默认参数不会在编译时进行评估。每次函数调用需要它们时都会对它们进行评估。它们可以是在函数声明的上下文中有效且具有合适类型的任何表达式,但它不能使用任何其他参数(包括this,在成员函数的情况下)。

该限制是因为未指定评估顺序,因此如果需要评估另一个参数,则无法确保参数值可用。

【讨论】:

  • 您能否提供一个示例代码来说明评估顺序很重要,在这种情况下使用非静态默认参数会导致问题?
【解决方案3】:

我认为这是可以理解的: g_x 和 s_x 在编译时可用,但 this(因此 this->m_x)不可用。 你可以使用一个技巧来使用m_x:

int b(int x = -1) { return x == -1 ? m_x + 1 : x + 1; }

(当然-1在这种情况下应该是非法输入。)

【讨论】:

  • 但它们在编译时不可用。它们不是const,因此该值可能会在运行时发生变化,并且对于每个函数调用都不同。
  • 迈克,你混合了两件事:值不可用,但对象(地址)在编译时可用。拥有一个从中获取默认值的地址就足够了。无论如何(即使您使用 const 或文字),您只有一个简单的值所在的地址。
猜你喜欢
  • 2018-04-30
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-04
  • 1970-01-01
相关资源
最近更新 更多