2011-03-31 15 views
3

我試圖實現我自己的bind_range,它可以與範圍綁定。它應該允許客戶像這樣的代碼:針對範圍綁定函數以實現迭代功能

void f(int x, int y) 
{ 
    std::cout << x + y << ','; 
} 

std::vector<int> v1; // contains 1,2,3 

void go() 
{ 
    boost::function<void(int y)> f_bound = bind_range(f, v1, _1); 
    f_bound(10); // prints 11,12,13, 
} 

在上面的代碼,我的模板bind_range檢測v1符合ForwardRangeConcept<>和它的值類型是f()的第一個參數兼容。然後它會生成一個函數對象,它將遍歷v1,爲每個值調用f()

我知道上面的代碼可以用調用代碼中的每個構造的某種形式來實現,但我想要綁定函數並稍後使用它。

以上是我想達到的本質。我已閱讀我的C++ Template Metaprogramming副本,並查看boost::bind實施,但我無法開始解決方案。我也有一種嘮叨的感覺,像這樣的東西已經存在於Boost圖書館的某處。

擴展:

綁定多個範圍。例如:

std::vector<int> v10; // contains 10,20,30 

void go_multiple() 
{ 
    boost::function<void()> f_bound = bind_range(f, v10, v1); 
    f_bound(); // prints 11,12,13,21,22,23,31,32,33, 
} 

與返回類型的處理。我不需要從我的迭代調用返回類型,但可以想象有人可能想要存儲或處理每個返回值。我確信這可以用某種Lamda型構造完成。

回答

0

我曾在這一點,這裏是我想出了。它可以工作,但是不完整,因爲只有一元函數和二元函數的模板,其範圍被綁定到第一個參數。如果有人進一步採取這種做法,使其更通用,請回到這裏。

#include <boost/bind.hpp> 
#include <boost/range.hpp> 
#include <boost/range/value_type.hpp> 
#include <boost/type_traits/function_traits.hpp> 
#include <boost/foreach.hpp> 

template <class Range> 
struct GetRangeValue 
{ 
    typedef typename boost::range_value<Range>::type Value; 
}; 

template <class Function, class Range> 
struct BindForEachBase 
{ 
    BindForEachBase(Function *f, Range &r) : function(f), range(r) { } 
    Function *const function; 
    Range &range; 
}; 

template <class Function, class Range> 
struct BindForEach1 
    : BindForEachBase<Function, Range> 
{ 
    BindForEach1(Function *f, Range &r) 
     : BindForEachBase(f, r) 
    { } 
    void operator()() 
    { 
     BOOST_FOREACH(GetRangeValue<Range>::Value v, range) (*function)(v); 
    } 
}; 

template <class Function, class Range> 
BindForEach1<Function, Range> 
bindForEach(Function *f, Range &r) 
{ 
    return BindForEach1<Function, Range>(f, r); 
} 

template <class Function, class Range, class A1> 
struct BindForEach2 
    : BindForEachBase<Function, Range> 
{ 
    BindForEach2(Function *f, Range &r) 
     : BindForEachBase(f, r) 
    { } 
    void operator()(A1 a1) 
    { 
     boost::function1<void, GetRangeValue<Range>::Value> f(boost::bind(*this->function, _1, a1)); 
     bindForEach(&f, range)(); 
    } 
}; 

template <class Function, class Range, class Placeholder1> 
typename boost::enable_if 
< 
    boost::is_placeholder<Placeholder1>, 
    BindForEach2<Function, Range, typename boost::function_traits<Function>::arg2_type> 
>::type 
bindForEach(Function *f, Range &r, Placeholder1 p1) 
{ 
    return BindForEach2<Function, Range, boost::function_traits<Function>::arg2_type >(f, r); 
} 

void f(int x, int y) 
{ 
    std::cout << x + y << ','; 
} 

#include <boost/assign/std/vector.hpp> 
#include <vector> 
using namespace boost::assign; 

void go() 
{ 
    std::vector<int> v1; 
    v1 += 1,2,3; 
    boost::function<void(int y)> f_bound = bindForEach(f, v1, _1); 
    f_bound(10); // prints 11,12,13, 
} 
0

我沒有看到問題所在。你說這可以通過調用代碼中的for_each構造來實現。是的。那麼爲什麼不把那個for_each構造放入bind_range函數本身呢?我的意思是,bind_range將會是一個帶有operator()的結構模板。在這個操作符中,你必須做一個for_each。我錯過了什麼嗎?

+0

也許這是一個簡單的解決方案。我想我開始喜歡的東西'模板<....>結構bind_range:提高::綁定<....> {};'然後去上專門在那裏一個參數是每種情況下??? – paperjam 2011-03-31 09:34:45

3

據我所知,這並不在升壓存在的,因爲它很容易與for_eachbind轉載,例如:

function<void()> bound = bind(
    for_each<vector<int>::iterator, function<void(int)> >, 
    v1.begin(), v1.end(), func 
);` 

這是相當簡單的。你只需要創建一個模板函子bind_range帶有一個構造函數,該構造函數接受綁定信息(即容器和函子)以及將該函數應用於容器的operator()

但是,請注意,保存一個像這樣的函子以備後用時往往是危險的,因爲bind_range對象可能最終引用一個不再存在的容器。

一個簡單的例子:

template<typename Container, typename Function> 
struct bind_range { 
    bind_range(Container& target, Function func) 
     : container(target), function(func) { } 

    void operator()() { 
     std::for_each(container.begin(), container.end(), function); 
    } 

    Function function; 
    Container& container; 
}; 
+0

這工作,我認爲其中'Function'是一元的最簡單的情況。但我想用佔位符,即'_1'等我建你的榜樣,看看我現在只是一個小小的一步之遙綁定。 – paperjam 2011-03-31 13:36:41

+0

爲了支持N進制的功能,你只需要創建模板'運營商()'重載取N個參數。另外請注意,您可以創建一個功能,如Boost.Bind做,而不需要用戶明確說明模板參數返回一個'bind_range'對象。 – 2011-03-31 14:15:48