使用标准构造函数传递临时对象

Posted

技术标签:

【中文标题】使用标准构造函数传递临时对象【英文标题】:Pass temporary object with standard constructor 【发布时间】:2012-02-29 02:04:46 【问题描述】:

我想将一个临时对象(例如 std::string)传递给我的对象的构造函数:

class MyClass
  public:
    MyClass(string a):
      a(a)
    

    
    string a;
;

int main(int argc, char *argv[])
  MyClass a(string());
  cout<<a.a<<endl;
  return 0;

但我收到此错误:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:28:11: error: request for member ‘a’ in ‘a’, which is of non-class type ‘MyClass(std::string (*)()) aka MyClass(std::basic_string<char> (*)())’

如果我将任何内容传递给临时对象的构造函数(例如字符串(“”)),一切正常。为什么?

【问题讨论】:

【参考方案1】:

这是被称为 C++ 的most vexing parse 的一个实例。编译器解释

MyClass a(string());

作为名为@9​​87654323@ 的函数的原型,返回一个MyClass 并以一个未命名的string 作为参数。

您可以通过在对strings 构造函数的调用加上括号来消除歧义:

MyClass a((string()));

或者,只要MyClass 具有可访问的复制构造函数:

MyClass a = string();

C++11 更新

您也可以使用通用初始化语法消除歧义,只要您的类没有采用 initializer_list 的构造函数:

MyClass a  string() ;

【讨论】:

这表示“编译器将 'MyClass a(string())' 解释为名为 'a' 的函数的原型,该函数返回一个 'MyClass' 并将一个未命名的 'string' 作为参数。”这是不正确的。应该说编译器将其解释为名为 'a' 的函数的原型,该函数返回一个 'MyClass',并将一个 函数返回值为 'string' 作为其唯一(未命名的)参数。跨度> 【参考方案2】:

正如 Seth 已经指出的那样,这是语言和表达式解析方式的问题。基本上,当编译器找到表达式MyClass a(string()) 时,它会将其解释为具有签名MyClass (std::string (*)()) 的函数a 的声明(额外的(*) 来自从函数到参数中函数指针的隐式转换)。

在您的特定情况下,有不同的方法可以克服该语法:

MyClass a("");                // 1
MyClass b = std::string();    // 2
MyClass c(( std::string() )); // 3

第一种方法不是使用T() 表达式来创建右值,而是使用将产生相同输出的常量文字。这种方法的缺点是,在这种特殊情况下,您可以使用文字,但不能将相同的解决方案应用于其他类型(即,如果您有自己的类型,但只有默认构造函数)

第二种方法是避免直接初始化,因为替代语法不能被解析为函数声明。这种方法的问题在于,虽然您的特定情况下的结果是相同的,但它要求构造函数不是显式。 (即,如果您的构造函数被声明为 explicit MyClass( std::string const &amp; ),它将失败),但它没有

第三种方法是在构造函数的第一个参数周围添加一组额外的括号(请注意,解析中的相同问题也会发生在 MyClass a(std::string(), std::string()) 中)。这种方法(观点)的问题在于它很丑陋,但它是三种方法中最灵活的。

【讨论】:

以上是关于使用标准构造函数传递临时对象的主要内容,如果未能解决你的问题,请参考以下文章

为啥在通过 const 引用传递临时值时调用复制构造函数?

c++,类的对象作为形参时一定会调用复制构造函数吗?

Kotlin类与对象 ② ( 主构造函数 | 主构造函数定义临时变量 | 主构造函数中定义成员属性 | 次构造函数 | 构造函数默认参数 )

构造其构造函数采用单个枚举参数的临时对象时出错

为啥通过构造函数返回对象时没有临时对象?

C++:调用临时对象的构造函数