2013-04-11 113 views
1

我剛剛遇到了一個奇怪的含糊不清的問題,這個問題花了我很多時間來隔離,因爲它在API更改後突然出現在某些模板混亂的中間。作爲構造函數參數的構造函數調用將聲明作爲函數指針進行評估

以下示例探討調用構造函數的不同方法(或者我認爲的),其中一些對我來說很模糊。在他們所有人中,我試圖聲明A類型的對象。

#include <vector> 
#include <cstdlib> 
#include <iostream> 
#include <typeinfo> 
using namespace std; 

// just a dummy class to use in the constructor of the next class 
struct V { 
    V(const std::vector<size_t> &){} 
}; 

// the class we are interested in 
struct A{ 
    A(const V &){} 
    A(int, const V &){} 
    A(const V &, int){} 
    A(const V &, const V &){} 
}; 

// a dummy function to delegate construction of V 
V buildV(std::vector<size_t> &v){ return V(v); } 

int main(){ 
    std::vector<size_t> v = {1024,1024}; 
    V vw(v); 

    // I am using macros to make the constructor argument more visible 
    #define BUILD_A(X) { A a(X); std::cerr << typeid(a).name() << std::endl; } 
    #define BUILD_A2(X,Y) { A a(X, Y); std::cerr << typeid(a).name() << std::endl; } 

    // All of the following call the constructor of A with different parameters 
    // the comment on the right shows the type of the declared a 
    /* 1 */ BUILD_A(vw)      // object 
    /* 2 */ BUILD_A(V(v))      // function pointer 
    /* 3 */ BUILD_A(v)      // object 
    /* 4 */ BUILD_A(std::vector<size_t>()) // function pointer 
    /* 5 */ BUILD_A((V)V(v))     // object 
    /* 6 */ BUILD_A((V(v)))     // object 
    /* 7 */ BUILD_A(buildV(v))    // object 

    /* 8 */ BUILD_A2(10,V(v))     // object 
    /* 9 */ BUILD_A2(V(v),10)     // object 
    /* 10 */ BUILD_A2(vw,V(v))     // object 
    /* 11 */ BUILD_A2(V(v), vw)     // object 

    /* 12 */ //BUILD_A2(V(v), V(v))    // doesn't compile 
    /* 13 */ BUILD_A2(V(v), (V)V(v))   // object 
} 

第二和第四實施例似乎聲明一個函數指針,而不是一個對象,這引起了幾個問題:

  1. 爲什麼V(v)解釋爲類型,而不是爲A a(V(v))對象?
  2. 如何解析V(v)(V)V(v)解釋不同?
  3. 爲什麼編譯器無法推斷出演員本身?
  4. 6中的雙括號((...))是否具有語義含義,還是僅僅有助於消歧解析器?我不明白這可能是一個優先問題。
  5. 如果V(v)的計算結果爲Type而不是對象,爲什麼A a(V(v), V(v))在12中不合法?
  6. 有趣的是,添加一個標量值突然讓編譯器意識到另一個對象也在8到11之間。
  7. 我是否錯過任何會重現歧義的語法?你知道任何其他令人困惑的情況嗎?
  8. 不應該GCC警告我那裏可能有問題嗎?鏗鏘。

感謝,

+0

請參閱http://en.wikipedia.org/wiki/Most_vexing_parse – JBentley 2013-04-11 19:05:29

回答

1

這就是所謂的最棘手的解析:嘗試的聲明被解析爲函數聲明。

C++規則是,如果某些東西可以被解析爲一個函數聲明,它將會是。

有一些變通辦法,如寫作A a((V(v))),不能被解析爲一個功能a的一個V參數並返回A聲明。


關於警告,標準不需要任何診斷。畢竟,潛在的不明確性已經解決。贊成功能。 :-)

+0

這解釋了我的大部分觀點。我仍然不確定爲什麼'A a(V(v),V(v))'也不合法。難道它不是一個帶兩個無名參數的函數嗎? – Thibaut 2013-04-20 14:58:13