无法将 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)
,其中 e
是 A
范围内的枚举器。
我相信这段代码仍然符合声明的语法规则。参见[dcl.decl]/4语法规范(部分):
noptr-declarator: declarator-id attribute-specifier-seqopt
declarator-id: ...opt id-expression
和id-expression可以是qualified-id或unqualified-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
看到这个编译错误,我有点吃惊;
示例如下:
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)
,其中 e
是 A
范围内的枚举器。
我相信这段代码仍然符合声明的语法规则。参见[dcl.decl]/4语法规范(部分):
noptr-declarator: declarator-id attribute-specifier-seqopt
declarator-id: ...opt id-expression
和id-expression可以是qualified-id或unqualified-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