奇怪的编译器决策

4

I've got the following code:

enum nums {
  a
};

class cls {
public:
  cls( nums );
};

void function()
{
  cls( a );
}

当我尝试使用gcc编译时,出现以下错误:
test.cpp: In function ‘void function()’:
test.cpp:12:10: error: no matching function for call to ‘cls::cls()’
test.cpp:12:10: note: candidates are:
test.cpp:7:3: note: cls::cls(nums)
test.cpp:7:3: note:   candidate expects 1 argument, 0 provided
test.cpp:5:7: note: cls::cls(const cls&)
test.cpp:5:7: note:   candidate expects 1 argument, 0 provided
make: *** [test] Error 1

如果我用以下代码替换该函数:
void function()
{
  cls name( a );
}

然后一切正常。如果我使用带有两个参数的构造函数,也可以正常工作。如果我在构造函数中添加“explicit”,则无法正常工作。
我知道gcc以某种方式解析它,将其定义为类型为“cls”的变量,并将其命名为“a”,但我对定义变量的这种语法并不熟悉。在我看来,这是一个语句,定义了一个匿名临时变量,其类型为cls,将“a”作为参数传递。
使用gcc 4.6.3编译。
有什么见解吗?
谢谢, Shachar

“cls(a);”应该做什么?你有什么想法?! - Kerrek SB
根据问题所述 - 创建一个类型为“Cls”的临时对象。 - Shachar Shemesh
2个回答

10

另一个最尴尬的解析问题的例子。这一行:

cls( a );
声明一个名为a、类型为cls的本地变量,应通过调用默认构造函数进行初始化,但是该构造函数不存在,因此会出现错误消息。
如果你真的想构建一个临时对象,在其被销毁之前立即使用,可以将整个表达式放在括号中以消除歧义:
(cls( a ));

定义不能出现在括号中;表达式可以。


8
括号是可选的,因此 cls (a);cls a; 相同,它声明了一个类型为 cls 的对象 a 并对其进行默认初始化(这会失败,因为没有匹配的构造函数)。
要创建一个在表达式结束时过期的临时值,可以在 C++11 中使用 cls { a };(cls(a));(或任意数量的更奥妙的结构,如void(0), cls(a);)。
有关更多想法,请参见this answer

类似于“最令人烦恼的解析”。 - gx_
@KerrekSB 表示,如果存在歧义,语句将成为“声明”,而不是表达式语句,这并不总是函数声明;这就是为什么我说“类似”,因为“典型”的 MVP 意味着一个不需要的函数声明,而这个问题则意味着一个不需要的变量声明。(所以我的评论并不是批评,只是一条评论 :)) - gx_
@KerrekSB 这些括号被允许的直接原因是什么? - johnchen902
2
@johnchen902:有时候你必须要能够显式地分组类型名称的部分,所以这是一个通常很有用的特性,比如在(int *)[10]中,与int * [10]不同。 - Kerrek SB
1
@KerrekSB,应该使用int (*p)[10](指向数组的指针)而不是int* a[10](指针数组)("(int *)[10]" 不是有效的语法)。 - gx_
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接