2012-02-29 49 views
2

我想一個臨時對象(的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(「」)),那麼一切正常。爲什麼?

回答

6

這是一個被稱爲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

這就是說:「編譯器將'MyClass a(string())'解釋爲名爲'a'的函數的原型,返回'MyClass'並將未命名的'string'作爲參數。這是不正確的。它應該說編譯器將它解釋爲一個名爲'a'的函數的原型,它返回一個'MyClass'並將帶有'string'返回值*的*函數作爲其唯一(未命名)參數。 – 2015-01-15 03:30:25

2

因爲它已經被賽斯指出,這是與語言,以及如何表達解析的問題。基本上,當編譯器找到表達式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())發生)。這種方法(觀點)的問題是它很醜,但它是三者中最靈活的。