2012-01-30 59 views
7

我想構建一個靜態綁定的委託類,其中成員函數在編譯時綁定,從而幫助優化。指向成員函數的模板參數推導?

我有下面的代碼的工作正是我希望它:

#include <iostream> 

namespace thr { 

template<typename T, T func> 
struct delegate; 

template<typename R, 
     typename C, 
     typename... A, 
     R (C::* mem_fun)(A...)> 
struct delegate<R(C::*)(A...), mem_fun> 
{ 
    delegate(C* obj_) 
    : _obj(obj_) 
    {} 

    R operator()(A... a) 
    { 
    return (_obj->*mem_fun)(a...); 
    } 
private: 
    C* _obj; 
}; 

} // namespace thr 

struct foo 
{ 
    double bar(int i, int j) 
    { 
    return (double)i/(double)j; 
    } 
}; 

int main() 
{ 
    foo f; 

    typedef thr::delegate<decltype(&foo::bar), &foo::bar> cb;  
    cb c(&f); 

    std::cout << c(4, 3); 
    return 0; 
} 

但是,使用不是很優雅:

thr::delegate<decltype(&foo::bar), &foo::bar> 

我想用一個函數模板,推導出模板參數並返回委託實例;沿(此代碼不能編譯)線的東西:

template<typename C, typename T, T func> 
thr::delegate<T, func> bind(T func, C* obj) 
{ 
    return thr::delegate<decltype(func), func>(obj); 
} 

這將使更優雅的語法:

auto cb = bind(&foo::bar, &f); 

是否有可能推導出一個函數模板非類型參數?

我試圖實現甚至可能嗎?

+0

有時可以在函數模板中推導一個非類型參數,例如'N'可以在'template size_t int_array_length(int(&array_ref)[N]){return N;}'中推導出來。但是'N''儘管不是一個類型本身,函數簽名中仍然有一部分類型。 – 2012-01-30 18:31:53

+1

添加一個宏:'#define MAKE_DELEGATE(x,y)thr :: delegate (y)'我看不到任何其他方法來避免命名該函數兩次。 – 2012-01-30 18:49:05

+0

@Iori:你知道在你的例子中,'T'是'func'的類型,所以'decltype'沒有必要:)? – 2012-01-30 19:44:05

回答

1

它可以推斷出其他實體比在函數簽名類型,但功能參數本身不能被用來作爲模板參數。

考慮:

template <size_t I> struct Integral { static size_t const value = I; }; 

您可以:

template <size_t N> 
Integral<N> foo(char const (&)[N]); 

但你不能有:

Integral<N> bar(size_t N); 

在前一種情況下,N作爲數組的大小是部分在後一種情況下,N就是論證本身。可以注意到,在前一種情況下,N出現在類型簽名的模板參數列表中。

因此,如果確實需要可能,成員指針將不得不作爲函數簽名的模板參數列表的一部分出現。

有可能是使用constexpr一個救命之恩,它可以把一個普通值進入恆定適合模板參數:

constexpr size_t fib(size_t N) { return N <= 1 ? 1 : fib(N-1) + fib(N-2); } 

Integral<fib(4)> works; 

但我不是足夠精明,這條路走...

但是我確實有一個簡單的問題:你爲什麼認爲這會加快速度?編譯器非常擅長不斷的傳播和內聯,以便在編譯時能夠評估動態變量類型時,能夠內聯調用虛擬函數。你確定這值得流汗嗎?

4

std :: function help? http://www2.research.att.com/~bs/C++0xFAQ.html#std-function你的例子看起來非常接近。

我認爲編譯器提供的STL做了非常可怕的事情,使它工作順利。在放棄之前,你可能想看一看。

編輯:我出去了,試着嘗試完成。我的結論是編譯錯誤:

  • bind(委託)的返回類型必須將指針命名爲成員,因爲這是您自己的要求。
  • bind應該接受指針成員的名稱是優雅(即你的要求)
  • 編譯器需要你不是一個函數參數陰影模板參數或在兩個參數使用的名稱和返回類型。

因此,您的一個要求必須去。

編輯2:我冒昧地改變你的委託,所以綁定工作如你所願。綁定可能不是你的優先事項。

#include <iostream> 

namespace thr { 


template<typename C,typename R,typename... A> 
struct delegate 
{ 
private: 
    C* _obj; 
    R(C::*_f)(A...); 
    public: 
    delegate(C* obj_,R(C::*f)(A...)) 
    : _obj(obj_),_f(f) 
    {} 

    R operator()(A... a) 
    { 
    return (_obj->*_f)(a...); 
    } 

}; 

} // namespace thr 

template<class C,typename R,typename... A> thr::delegate<C,R,A...> bind(R(C::*f)(A...),C* obj){ 
    return thr::delegate<C,R,A...>(obj,f); 
} 

struct foo 
{ 
    double bar(int i, int j) 
    { 
    return (double)i/(double)j; 
    } 
}; 

int main() 
{ 
    foo f; 
    auto c = bind(&foo::bar, &f); 
    std::cout << c(4, 6); 
    return 0; 
} 
+0

'std :: function '僅在其模板參數中使用類型,並且沒有值。 – 2012-01-30 19:56:13

+0

據我所知,這個excersice的重點不是顯式鍵入委託類型。拍一個'auto'應該是可能的而且足夠的。 – artificialidiot 2012-01-30 20:09:56

+0

我不這麼認爲。我認爲目標是在沒有重複信息的前提下將指向成員函數的指針作爲模板參數(如示例中所示)。 – 2012-01-31 07:15:53

相關問題