2017-09-14 123 views
4

考慮這個非常簡單的代碼:C++函數定義和變量聲明不匹配?

#include <memory> 

class Foo 
{ 
public: 
    Foo() {}; 
}; 

class Bar 
{ 
public: 
    Bar(const std::shared_ptr<Foo>& foo) {} 
}; 

int main() 
{ 
    Foo* foo = new Foo; 
    Bar bar(std::shared_ptr<Foo>(foo)); 
    return 0; 
} 

爲什麼Visual Studio的報告

warning C4930: 'Bar bar(std::shared_ptr<Foo>)': prototyped function not called (was a variable definition intended?) 

並沒有創造......這怎麼行Bar bar(std::shared_ptr<Foo>(foo));被解釋爲一個函數的定義沒有bar對象?

我檢查Do the parentheses after the type name make a difference with new?C++: warning: C4930: prototyped function not called (was a variable definition intended?),但我覺得我的問題是不同的這裏,因爲我沒有使用語法Foo()也不Bar()

編輯:請注意,它成功編譯:

Foo* foo = new Foo; 
std::shared_ptr<Foo> fooPtr(foo); 
Bar bar(fooPtr); 
+9

C++最令人煩惱的解析。 –

+0

@眠りネロクno,gcc編譯它 –

+1

@RichardHodges所以MSVC,它只是一個警告。眠りネロク是正確的。 – Quentin

回答

14

這個問題是關於C++'s most vexing parse。聲明:

Bar bar(std::shared_ptr<Foo>(foo)); 

聲明瞭一個名爲bar返回Bar,並採取所謂std::shared_ptr<Foo>類型的foo參數的功能。

最裏面的括號不起作用。這是因爲如果你寫了下面的:

Bar bar(std::shared_ptr<Foo> foo); 

假設C++ 11(因爲你已經在使用std::shared_ptr),你可以使用支具語法代替括號

Bar bar(std::shared_ptr<Foo>{foo}); 

這實際上會構造一個Bar類型的對象bar,因爲上面的語句不能被解釋爲聲明,因爲的大括號。

+3

你的意思是它相當於'Bar bar(std :: shared_ptr foo);'? – jpo38

+2

正確,但如果您有關於最煩人的解析的解釋或鏈接並提供解決方案,可能會更好。 – aschepler

+0

可能的C++ 98或TR1解決方案是在預期的變量名後使用雙括號。正如您所指出的那樣,參數名稱可以包含在免費括號中,但不包括整個參數列表,即使它只包含一個參數聲明。所以,例如:''酒吧((std :: tr1 :: shared_ptr (foo))''。雖然不太可讀 –