2013-03-08 99 views
3

方法指針我有這樣的功能:模板在鐺VS GCC和MSVC

template <typename T, void (T::*pf)()> 
void call(T& t) 
{ 
    (t.*pf)(); 
} 

如果我有foo類與適當的簽名的方法(比如bar)我可以這樣調用call<foo, &foo::bar>();,它的精細。但是,如果barconst gcc和msvc很樂意在調用像這樣的call<const foo, &foo::bar>()時編譯它。鏗鏘聲稱第二個模板參數無效。當我將const放在模板參數(​​)中時,所有的樹都會編譯它。

現在,這不是一個大問題,但是如果我不必在模板參數中編寫這個可憐的const,我的代碼將變得更加乾淨。

所以問題基本上是:標準對此有何評論?這是一個鏗鏘聲bug還是gcc和msvc只是讓它滑動,因爲它們很酷?

PS這裏有一個完整的攝製程序的鏈接:http://codepad.org/wDBdGvSN

+3

Clang在這裏,指向const限定成員函數的指針的類型是'R(C :: *)(Args)const',不能轉換爲非const類型。 – Xeo 2013-03-08 12:10:39

+0

但是我猜你可能會說'R(C :: *)(Args)const'與這個(無效但可以理解)相同:'R(const C :: *)(Args)' – 2013-03-08 12:17:00

+0

不,它不是一模一樣。前一個版本仍然可以在非const的'C'對象上完美調用。 – Xeo 2013-03-08 12:18:49

回答

2

const -ness的方法之一是它的「簽名」的一部分。因此,定義和使用一個成員指針的正確方法是:

R (Obj::*)(Args)  // for non-const member 
R (Obj::*)(Args) const // for const member 

。請注意,const成員可以稱爲非const對象,這是不符合R (const Obj::*)(Args)的情況。

解決這種情況的方法是抽象這樣的函數指針,通過定義「呼叫包裝」:

template<typename O, void (O::* f)()> 
struct NonConstFunc 
{ 
    static void call(O* o) 
    { 
     (o->*f)(); 
    } 
}; 

template<typename O, void (O::* f)() const> 
struct ConstFunc 
{ 
    static void call(O* o) 
    { 
     (o->*f)(); 
    } 
}; 

然後,您可以使用它通過以下方式(這裏的抽象發生):

template<typename Obj, typename Function> 
void call(Obj* o) 
{ 
    Function::call(o); 
} 

有一個live example here

這只是主要想法。您可以在不更改用戶代碼的情況下,自動檢測方法是否爲const並將其擴展。

+0

我最終做了一件非常相似的事情。謝謝。 – 2013-03-08 14:57:45

+0

誰在指定功能?用戶,還是你的代碼? – Synxis 2013-03-08 17:42:27