2012-12-01 33 views
4

有人能解釋一個模板方法時,爲什麼下面的C++代碼不表現爲預期:以上奇怪的編譯行爲的呼籲從另一個模板對象

struct Object { 
    template< int i > 
    void foo(){ } 
}; 

template<int counter> 
struct Container { 
    Object v[counter]; 

    void test(){ 
    // this works as expected 
    Object a; a.foo<1>(); 

    // This works as well: 
    Object *b = new Object(); b->foo<1>(); 

    // now try the same thing with the array: 
    v[0] = Object(); // that's fine (just testing access to the array) 

# if defined BUG1 
    v[0].foo<1>(); // compilation fails 
# elif defined BUG2 
    (v[0]).foo<1>(); // compilation fails 
# elif defined BUG3 
    auto &o = v[0]; 
    o.foo<1>();  // compilation fails 
# else 
    Object &o = v[0]; 
    o.foo<1>();  // works 
# endif 
    } 
}; 

int main(){ 
    Container<10> container; 
} 

代碼編譯罰款沒有標誌。如果標誌BUG1到BUG3之一被設置,則編譯失敗,GCC 4.6或4.7以及3.2版(這似乎表明它不是GCC錯誤)。

21到29行在語義上完成同樣的事情(即調用Object數組的第一個元素的方法),但只有最後一個版本編譯。這個問題似乎只在我嘗試從模板對象調用模板化方法時出現。

BUG1只是編寫調用的「正常」方式。

BUG2是同樣的事情,但是如果存在優先級問題(但不應該有),則數組訪問受括號保護。

BUG3顯示類型推斷不工作(需要用C++ 11支持編譯)。

上一個版本可以正常工作,但我不明白爲什麼使用臨時變量來存儲引用可以解決問題。

我很想知道爲什麼其他三個是無效的。

感謝

+1

嘗試'v [0] .template富<1>();'。 –

+0

@KerrekSB:有趣的是爲什麼這是必要的。看起來v [0]不是依賴表達式,因此編譯器應該能夠在解析模板時解析其類型。 –

+0

@VaughnCato:我還沒有測試過,我也不確定。這只是一個建議......畢竟,OP並沒有告訴我們錯誤是什麼,只有這麼多的猜測才能做到。 –

回答

1

你必須使用template爲:

v[0].template foo<1>(); 

auto &o = v[0]; 
o.template foo<1>();  

由於v聲明依賴於模板參數,這使得v一個從屬名稱。

這裏template關鍵字告訴編譯器,無論走的是一個模板(在你的情況,foo的確是一個模板)。如果foo不是模板,則不需要template關鍵字(實際上,這將是一個錯誤)。

的問題是,o.foo<1>()可以分析/解釋有兩種方式:一種是就像你希望(函數調用),另一種方式是這樣的:

(o.foo) < 1 //partially parsed 

就是foo是成員數據(而不是函數),並且您將其與1進行比較。因此,要告訴編譯器<不用於比較o.foo1,而是用於將模板參數1傳遞給函數模板,則需要使用template關鍵字。

+0

但是,如果foo不是模板方法,那麼它爲什麼會起作用?這個問題似乎並不來自第 – Thibaut

+0

@Thibaut:編輯。 – Nawaz

+0

謝謝,非常明確的解釋。任何想法爲什麼類型推斷在第三種情況下也失敗了?我認爲auto關鍵字會以與手動聲明類型相同的方式消除歧義。 – Thibaut

1

裏面的模板,表達式可以是類型依賴的值依賴的。從14.6起。2:

類型和表達式可以取決於類型和/或模板的值參數

在你的情況,counter是模板參數,以及v聲明取決於它,使v[0]一個值依賴的表達式。因此,該名foo是從屬名稱,你必須說歧義作爲模板名稱:

v[0].template foo<1>(); 
+0

是的!數組的大小是依賴於數值的,這使得數組類型是依賴於類型的,使得名稱'v'是取決於值的,使得表達式'v [0]'取決於數值。 –