编译错误:临时对象构造函数缺少参数

3

在一个作用域内创建临时对象时,编译器无法看到提供给构造函数的参数并会产生编译错误。

例如,以下代码就会出现这种情况:

#include <sstream>
#include <iostream>

class csventry
{
public:
        csventry(std::ostream& ostream) :
                _ostream(ostream)
                {}

        ~csventry() 
                { _ostream << std::endl; }

        csventry& operator << (const std::string& value) {
                _ostream << ", ";
                _ostream << value;
                return *this;
        }

private:
        std::ostream& _ostream;
};

int main () 
{
        std::ostringstream log;

        { csventry(log) << "User Log-on:"; }
        { csventry(log); }
        { csventry(log) << "Summary:"; }

        std::cout<<log.str()<<std::endl;
}

我遇到了一个错误。
main.cpp: In function ‘int main()’:
main.cpp:29:16: error: no matching function for call to ‘csventry::csventry()’
  { csventry(log); }
                ^
main.cpp:7:2: note: candidate: csventry::csventry(std::ostream&)
  csventry(std::ostream& ostream) :
  ^~~~~~~~
main.cpp:7:2: note:   candidate expects 1 argument, 0 provided
main.cpp:4:7: note: candidate: constexpr csventry::csventry(const csventry&)
 class csventry
       ^~~~~~~~
main.cpp:4:7: note:   candidate expects 1 argument, 0 provided

我尝试使用gcc 7.3和5.4

当我给临时对象命名时,它可以工作,{ csventry entry(log); }

为什么编译器会忽略提供的参数?


我不确定会发生什么,但我有一个小的解决方法:在coliru上进行实时演示。(我引入了一个辅助函数。) - Scheff's Cat
1
请仅返回翻译后的文本:为什么C++允许我们在声明变量时用括号括起变量名? - NathanOliver
顺便问一下,为什么需要将临时变量放入作用域中?如果不这样做,您会更早地捕获错误的原因。 - Slava
1个回答

10

csventry(log);并不像你期望的那样创建一个临时对象; 实际上,圆括号被认为是多余的。它声明了一个名为log的对象,类型为csventry,换句话说,它与csventry log;相同。如错误消息所示,它失败是因为csventry没有默认构造函数。

解决方法是将其更改为csventry{log};

[stmt.ambig]/1:

(我加粗了)

语法中存在一种表达式语句和声明之间的歧义:最左边的子表达式是带有函数风格的显式类型转换的表达式语句,可以与第一个声明符以 ( 开始的声明无法区分。在这些情况下,该语句是一个声明


为什么会被这样解释?这是在标准中定义的吗? - Yksisarvinen
2
@Yksisarvinen 因为你可以在声明中使用(),例如 int (*funcptr)(); - Slava
1
@Yksisarvinen 引用了标准中的内容。 - songyuanyao
啊,我现在明白了,没有考虑到函数指针。还有感谢标准片段! :) - Yksisarvinen

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