我想将一个临时对象(例如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> (*)())}’
如果我将任何内容传递给临时对象的构造函数(例如string(“”)),那么一切正常。为什么呢?
答案 0 :(得分:8)
这是被称为C ++ most vexing parse的实例。编译器解释
MyClass a(string());
作为名为a
的函数的原型,返回MyClass
并将未命名的string
作为参数。
您可以通过在string
构造函数的调用周围加上括号来消除歧义:
MyClass a((string()));
或者,只要MyClass
具有可访问的复制构造函数:
MyClass a = string();
更新C ++ 11
您也可以使用通用初始化语法消除歧义,只要您的类没有带initializer_list
的构造函数:
MyClass a { string() };
答案 1 :(得分:2)
正如Seth已经指出的那样,这是语言的问题以及如何解析表达式。基本上,当编译器找到表达式MyClass a(string())
时,它会将其解释为具有签名a
的函数MyClass (std::string (*)())
的声明(额外(*)
来自函数的隐式转换指向参数中的函数。)
在您的特定情况下,有不同的方法可以克服这种语法:
MyClass a(""); // 1
MyClass b = std::string(); // 2
MyClass c(( std::string() )); // 3
第一种方法不是使用T()
表达式来创建rvalue,而是使用将产生相同输出的常量文字。这种方法的缺点是在这种特殊情况下你可以使用文字,但同样的解决方案不能应用于其他类型(即如果你有自己的类型只有默认构造函数)
第二种方法是避免直接初始化,因为替代语法不能被解析为函数声明。这种方法的问题在于,虽然在特定情况下的结果是相同的,但它要求构造函数不要显式。 (即,如果你的构造函数被声明为explicit MyClass( std::string const & )
),它将会失败,但它没有
第三种方法是在构造函数的第一个参数周围添加一组额外的括号(请注意,MyClass a(std::string(), std::string())
)解析时会出现同样的问题。这种方法(意见)的问题在于它是丑陋的,但它是三者中最灵活的。