无法将 class 实例化为具有合格枚举作为参数的 LHS 值 (C++ VS2015)

Can not instantiate class as LHS value with qualified enum as argument (C++ VS2015)

看到这个编译错误,我有点吃惊;

示例如下:

class A
{
public:
  enum eA { eA1, eA2 };

  class B
  {
  public:
    B(eA e, int i = 0);
  };

  A(const B &b);
};

A::A(const B &b)
{
}

A::B::B(eA e, int i /*= 0*/)
{
}

int main()
{
  A::B b(A::eA1);        // OK
  A a0(b);               // OK
  A a1(A::B(A::eA1, 0)); // OK
  A a2(A::B(A::eA2));    //error C2751: 'A::eA2': the name of a function parameter cannot be qualified
  return 0;
}

正如评论中指出的那样,A a2(A::B(A::eA2)); 无法编译。为什么? 我不是问如何编译它。为什么它不能编译?

如果 class-B 的第一个参数类型不是来自 class-A,它会编译。例如 int 它编译。

这是一个最令人烦恼的解析问题。 canonical case 将是:

T t( U(x) );

其中 T 和 U 以前已知是类型名称。这可以用两种有效的方式解析:

  • t 声明为类型 T 的对象,初始值设定项是表达式 U(x),变量 x 的函数样式转换为临时 U
  • t 声明为返回 T 的函数,带有 1 个类型为 U 且名称为 x 的参数; x 周围有多余的括号。 (声明符可以用括号括起来)。

消除歧义标准中的文本在 [dcl.ambig.res]/1 中。它说的是解析这段代码取决于 U(x) 是声明还是表达式,然后引用 [stmt.ambig].

在 [stmt.ambig]/2 中有一个说明性的例子。我不会在这里重现完整的示例(您可以在标准草案中查找)但随附的文本是:

If the statement cannot syntactically be a declaration, there is no ambiguity

[...] This is of course ill-formed for semantic reasons, but that does not affect the syntactic analysis. In those cases the statement is a declaration.

这是想说的是,如果代码可以与声明的语言语法规则相匹配,那么它就是一个声明,即使代码随后违反了语义规则。


现在查看您的变体,其中内部代码是(简化的)U(A::e),其中 eA 范围内的枚举器。

我相信这段代码仍然符合声明的语法规则。参见[dcl.decl]/4语法规范(部分):

noptr-declarator: declarator-id attribute-specifier-seqopt

declarator-id: ...opt id-expression

id-expression可以是qualified-idunqualified-id,并且最后,A::e 是一个 qualified-id.

即使有语义规则 [dcl.meaning]/1 declarator-id 只能是 qualified-id 在某些情况下,除了这种情况,这不是语法规则。

所以我会说 VC 拒绝代码是正确的。


要修复代码,假设 a2 的意图是一个对象声明,您可以使用规范 MVP 线程中提到的相同技术:

A a2{A::B(A::eA2)};    // braced initialization

A a2((A::B(A::eA2)));  // function declarations can't have extra parentheses around the entire parameter declaration, so this cannot be a function declaration