使用临时对象调用构造函数

4

我不理解以下问题。

class InnerBox
{
public:
    InnerBox() : mContents(123) { };
private:
    int mContents;
};


class Box
{
public:

    Box(const InnerBox& innerBox) : mInnerBox(innerBox) { };

private:
    InnerBox mInnerBox;
};


void SomeFunction(const Box& box)
{
    return;
}

int main()
{
    Box box(InnerBox());  // !!PROBLEM!! Doesn't work: compiler thinks this is a function declaration
    SomeFunction(box);    // Error, cannot convert 'function pointer type' to const Box&

    return 0;
}

完整的错误信息是(Visual Studio 2010)
 error C2664: 'SomeFunction' : cannot convert parameter 1 from 'Box (__cdecl *)(InnerBox (__cdecl *)(void))' to 'const Box &'

解决方法很简单:
int main()
{
    InnerBox innerBox;
    Box box(innerBox);  
    SomeFunction(box);

    return 0;
 }

这是一个MSVC特有的问题吗?如果不是,有人可以解释一下语言的什么怪癖阻止我调用Box box(InnerBox());吗?


我编辑了标题以最好地反映问题。指出标题中的错误对于其他遇到相同问题的人没有太大帮助。如果有人和你一样遇到了同样的问题,他们不太可能知道什么是“最烦人的解析”,因此更不可能找到这个问题和答案。 - Luchian Grigore
没错。无论如何 - 现在非常明显,这是一个非常普遍的问题,但我在大约6年的C++开发中从未遇到过它,并且在网上找了几个小时也没有找到答案...肯定是我迄今为止遇到的“最令人烦恼”的问题! - Zero
3个回答

5
您需要将其写成以下形式:
Box box((InnerBox()));

或者

Box box{InnerBox()};

这并不是MSVC特有的问题。在C++中,规则是将任何可能是声明的结构都视为声明。
没有额外的括号,代码将声明一个名为“box”的函数,返回一个“Box”,其单个参数是指向不带参数且返回一个“InnerBox”的函数的指针。(是的 - 当在函数参数中使用InnerBox()时,实际上声明了一个指向函数(未命名)的指针(这类似于当Box[]用作函数参数时实际上声明了一个指向Box的指针)。)

你能详细说明一下为什么吗?我无法理解编译器是如何得出 Box box(InnerBox()); 是函数声明的结论。此外,这个问题有一个术语吗?我是否可以通过搜索找到答案? - Zero

5
原始代码被解析为一个函数声明(而非定义),这个函数名为'box',返回一个Box类型,并且需要一个返回InnerBox类型并且不需要参数的函数指针作为其参数InnerBox (*)()。详情请见 this ,其中详细介绍了“最令人困扰的语法解析问题”。
您可以通过使用额外的括号Box box((InnerBox()));来明确区分对象的构造方式。或者稍微更加简洁的替代方案是,您可以使用新的C++11对象构造语法: Box box{InnerBox()};

4

这是一个MSVC特有的问题吗?如果不是,能否有人解释一下语言的哪个怪癖阻止我调用Box box(InnerBox())?

为了补充其他答案:

这被称为最让人烦恼的解析。这不是编译器的问题。基本上是一种解析规范,它表示可以视为声明的任何内容都将被视为声明。

在您的情况下,您可以通过以下方式进行修复:

Box box((InnerBox()));

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