c++閹割版binder實現
首先分析下binder的原理:為一個仿函式繫結幾個引數,或者用place holder改變引數的順序。首先實現不帶有place holder版本的binder,實現如下功能:一個binder類,構造的時候為仿函式按函式引數順序繫結若干個函式,過載operator(),輸入若干引數,內部呼叫仿函式,返回值為仿函式的返回值。根據功能分析可知,需要使用模板,因為繫結引數型別不一,可能需要一個tuple儲存繫結的引數。如下程式碼所示:
template <typename Func, typename RET, typename... Args>
class binder {
public:
binder(Func f1, Args... rest) :f(f1), t(rest...){
}
template <typename... Rest>
RET operator ()(const Rest&... rest) ;
private:
Func f;
tuple<Args...> t;
};
重要的是實現過載的operator(),傳入的引數個數可以用sizeof操作符得到,形如sizeof...(Args)。這個函式想要返回f(get<Nx>(t)...,rest...),想要得到這個序列可以通過一個輔助類和函式模板推導得到,程式碼比較直觀(可以通過檢視標準庫binder 的宣告,一步一步轉到定義檢視)
template <typename T,T... Args>
class Sequence {
public:
typedef Sequence<T, Args...> type;
typedef T value_type;
};
template <bool b,
size_t... args>
class Make_Seq {
};
template< size_t n,size_t... Args>
class Make_Seq<false,
n,
Args...> :public
Make_Seq<n <= 1,
n - 1,
n,
Args...>{
};
template<size_t... Args>
class Make_Seq<true,
0,
Args...>:public
Sequence<size_t,Args...>{
};
這個類實現比較巧妙,這是一個繼承鏈,最頂層的基類是Sequence,主要實現部分是中間那部分程式碼,從程式碼可以看出,從繼承鏈的最底層往上,每增加一個繼承,Args...就會增加一個n,即當前繼承的層數。有了這樣兩個輔助類就可以讓編譯器推匯出引數,實現如下:
template <size_t... args>
void func(const Sequence& s) {
}
func(Make_Seq(false, 10));
例子中就會推匯出args... = 1,2...10
有了這個輔助類,就可以實現operater()了,首先要寫一個函式用來引數推導,這個函式應該直接返回仿函式的結果,因為想要將過載operater()中的不定引數傳入這個函式中,因為函式模板推導中不能有兩個不定引數推導,所以應當把operator()中的引數以一個tuple傳入函式中,這樣也面臨前面同樣的問題。我想到的方法是,將要binder的那些引數組成的tuple當作第一個引數和operator()需要的引數一起放到一個tuple內,並且為tulple的get函式寫一個過載,當傳入引數不是tulple時,直接返回傳入的引數,實現如下:
template <int N, typename T>
inline
T
get(T&& a) {
return a;
}
這個就是過載的get,傳入tuple的get和tuple實現有關在這就不討論了。下面說一下怎麼實現,首先在過載函式體內構造一個tuple:
tuple<tuple<Args...>, Rest...> t_arry(t, rest...);
第一個引數為一個tuple即binder的引數,後面是過載函式的引數。我們想要這樣實現,對於仿函式f,想要返回f(get<Ix>(get<Nx>(t_arry))...),其中比較重要的是Nx的實現,在沒有place holder的情況下,當Ix不大於binder的引數個數時,Nx為1,反之,Nx 等於 Ix 減去binder的引數個數,並且這個引數要在編譯期確定,藉助下面的模板實現:
template<bool C,int N1,int N2>
class NSwitch {
};
template< int N1, int N2>
class NSwitch<false,N1,N2> {
public:
enum {N = N2};
};
template< int N1, int N2>
class NSwitch<true , N1, N2> {
public:
enum { N = N1 };
};
設繫結的引數個數為 n1,總共傳入仿函式的引數個數為n2,藉助上面的類實現如下:
NSwitch<n1 > Ix,1,0>::N * (Ix - n1)
binder完整實現如下:
template <typename Func, typename RET, typename... Args>
class binder {
public:
binder(Func f1,Args... rest) :f(f1) ,t(rest...)) {
}
template <typename... Rest>
RET operator ()(const Rest&... rest) {
tuple<tuple<Args...>, Rest...> t_arry(t, rest...);
return _Call<RET, sizeof...(Args)>(t, t_arry, Make_Seq<false, NSwitch<TestT<Args...>::N,sizeof...(Args),sizeof...(Args)+sizeof...(Rest)>::N>(), f);
}
private:
Func f;
tuple<Args...> t;
};
_Call的實現如下:
template <typename RET,
int size,
typename Func,
typename T1,
typename T2,
size_t... Ix>
RET _Call(T1& t1,
T2& t2,
Sequence<size_t, Ix...>& s,
Func f) {
return f(get<Ix>(get<1 +
NSwitch<Ix > size,1,0>::N * (Ix -size)>(t2))...);
}
這樣就實現了沒有place holder的binder,帶有place holder 的實現也類似,只需要加幾個輔助模板類,有空了再寫吧
相關文章
- 快速實現一個簡單閹割版的HashMapHashMap
- C++ binder 實現C++
- Binder系統_c++程式實現C++
- Android Binder實現示例(C/C++層)AndroidC++
- c++ 層實現binder服務樣例C++
- c++ binderC++
- binder 一個簡單的c++服務的實現,與callback實現C++
- 巧用Fiddler開啟運營商定製版路由器被閹割的功能,免去刷公版韌體的風險路由器
- binder c++ 類C++
- Binder Java層的實現原理分析Java
- 酷瓜雲課堂v1.3.6釋出,線上教育軟體,未閹割全功能開源
- Binder機制分析(2)——從MediaService中看Binder的實現和使用(1)
- Binder機制分析(2)——從MediaService中看Binder的實現和使用(2)
- Binder機制分析(3)—— 實現自己的Service
- c++版的NMS(非極大抑制)實現C++
- Android Binder設計與實現 - 設計篇Android
- 理解 Android Binder 機制(二):C++層AndroidC++
- android binder c++層-客戶端(c++) 呼叫 服務端(c++) 例子AndroidC++客戶端服務端
- [Hook] 跨程式 Binder設計與實現 - 設計篇Hook
- Binder學習(四)利用AIDL、Messenger實現IPCAIMessenger
- Android C++層使用Binder通訊的方法AndroidC++
- [C++]實現memcpyC++memcpy
- binder通訊例項之c++客戶端與c++服務端C++客戶端服務端
- Android通過繼承Binder類實現多程式通訊Android繼承
- 命令模式(c++實現)模式C++
- 堆排序(實現c++)排序C++
- 堆排序c++實現排序C++
- Binder總結篇2-Binder使用
- Binder總結篇1-Binder原理
- Binder學習(二)Binder機制解析
- 享元模式(c++實現)模式C++
- 中介者模式(c++實現)模式C++
- 橋接模式(c++實現)橋接模式C++
- 模板方法模式(c++實現)模式C++
- 狀態模式(c++實現)模式C++
- 字典樹及其C++實現C++
- 折半查詢(C++實現)C++
- C++程式設計實現C++程式設計