2012-07-31 64 views
14

已知模板參數可以是指向成員函數的指針。成員函數指針的模板參數推導

因此我可以這樣寫:

struct Bar 
{ 
    int fun(float x); 
}; 

template <int (Bar::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<&Bar::fun> FooBar; 

但如果我想的Bar類型本身是一個模板參數:

template <typename B, int (B::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<Bar, &Bar::fun> FooBar; 

現在,當我使用它,我必須寫Bar兩次!

我的問題是:有沒有辦法強制編譯器自動推斷類的類型?

的目標是這只是工作:

typedef Foo<&Bar::fun> FooBar; 
typedef Foo<&Moo::fun> FooMoo; 

回答

5

你可能應該在那裏寫上類名。但是,如果你真的想避免這種情況,你可以使用宏的邪惡魔法。簡單的版本是比較危險的:

#define TT(X) decltype(X), X 

template<typename T,T t> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

這將接受任何類型的非類型模板參數,你可能會遇到難以理解的錯誤,如果Foo實現只用指針到成員的作品。

使之成爲更加安全,你需要一元函數,它告訴你的類名:

template<typename T> struct member_ptr_traits; 

template<typename Class,typename Ret,typename... Args> 
struct member_ptr_traits<Ret (Class::*)(Args...)> 
{ 
    typedef Class class_type; 
    typedef Ret return_type; 
}; 

#define TT(X) member_ptr_traits<decltype(X)>::class_type , X 

template<typename T,int (T::*FUN)(float)> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

這些還兼具使用C++ 11所以他們不會與舊的編譯器工作。這個簡單的版本可以重寫爲使用舊的typeof或類似的編譯器擴展。重寫更安全的版本需要模擬可變模板。瞭解。

+0

其實,我使用醜陋的宏(這是一個庫內部的模板,所以沒有被誤用的真正風險)。無論如何,'member_ptr_traits'非常棒,因爲我實際上需要'T'類型。 – rodrigo 2012-07-31 19:38:04

7

答案很簡單:沒有沒有。

問題是,要使typedef Foo<&Bar::fun> FooBar;正常工作,模板必須具有單個非類型參數,但在聲明模板時該參數的類型將是未知的,這是無效的。另一方面,類型演繹從不應用於模板的參數(僅適用於函數模板的參數,但這些參數是函數的參數,而不是模板)。

+0

瞭解。所以也不可能做一個模板函數,不是嗎? – rodrigo 2012-07-31 19:35:22

+0

@rodrigo:如果您想將該模板參數作爲指向成員的是。問題是你是否需要指向成員的指針作爲模板參數,或者它可以是函數參數,可以推導出來。 – 2012-07-31 21:03:56

+0

是的,我需要它是一個模板參數,因爲它必須用於實例化一個嵌套模板。無論如何,感謝您的洞察 – rodrigo 2012-07-31 21:48:36

相關問題