5

我想将一个临时对象(例如 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> (*)())}’

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

4

2 回答 2

8

这是被称为 C++最令人烦恼的 parse的一个实例。编译器解释

MyClass a(string());

a作为名为返回 aMyClass并将未命名 的函数string作为参数的函数的原型。

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

MyClass a((string()));

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

MyClass a = string();

C++11 更新

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

MyClass a { string() };
于 2012-02-29T02:06:44.947 回答
2

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

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

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

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

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

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

于 2012-02-29T02:27:13.940 回答