2015-01-06 100 views
2

成員函數我想寫一個類test,其能夠存儲一個函數,其能夠通過由經典[first,last)迭代器對標識的元素的集合來迭代,即:C++與迭代器作爲參數

template <typename T> 
struct sum 
{ 
    template <typename I> 
    T operator()(I first, I last) const 
    { 
    T res = 0; 
    while (first != last) 
    { 
     res += *first; 
     ++first; 
    } 
    return res; 
    } 
}; 
//... 
int main() 
{ 
    test<double> t; 
    t.set(sum<double>); 
    double a[] {1.,2.,3.}; 
    std::cout << "Test (array) => " << t.call(a, a+3) << std::endl; 
    std::vector<double> v {1.,2.,3.}; 
    std::cout << "Test (vector) => " << t.call(v.begin(), v.end()) << std::endl; 
    std::list<double> l {1.,2.,3.}; 
    std::cout << "Test (list) => " << t.call(l.begin(), l.end()) << std::endl; 
} 

我以爲使用std::function,但我沒有做到這一點,因爲我無法聲明模板化的迭代器對。 可能的解決方法是以下,然而僅使用普通陣列(例如,double[]double*,與上述變量a),但不與其它容器(例如,像上述變量vl)工作原理:

template <typename T> 
class test 
{ 
public: 
    template <typename F> 
    void set(F f) 
    { 
    f_ = f; 
    } 
    template <typename I> 
    T call(I first, I last) const 
    { 
    return f_(first, last); 
    } 
private: 
    std::function<T(T*,T*)> f_; 
}; 

關於如何獲得正確行爲的任何想法?

注:我用GCC 4.9.2編譯= --std C++ 11

非常感謝你。

+0

我不認爲這是可能的存儲類型擦除仿函數,它有兩個迭代器並返回一個'T'。我能想到實現這一點的唯一方法是需要虛擬模板方法......這是不允許的。 – Barry

+0

我改變了主意:) – Barry

+1

我編輯了你的問題來取出你的答案(它不適合這個問題 - 你可能會單獨發佈它作爲答案)。但是,這也不是一個很好的解決方案,因爲(a)現在你正在施加潛在的巨大運行時間開銷,並且(b)在'T'(它是可複製的)上增加了人爲的需求。 – Barry

回答

2

你想要的是真正能夠構建一個:

std::function<T(FwdIter<T>, FwdIter<T>)> 

其中FwdIter<T>是某種類型擦除的類,它滿足ForwardIterator概念並被取消引用爲T。爲此,檢查出Boost.TypeErasure庫,在這裏我們可以這樣做:

#include <boost/type_erasure/any.hpp> 
#include <boost/type_erasure/operators.hpp> 
#include <boost/mpl/vector.hpp> 

using namespace boost::type_erasure; 

template <typename T> 
using FwdIter = any< 
    boost::mpl::vector< 
     copy_constructible<>, 
     incrementable<>, 
     dereferenceable<T>, 
     equality_comparable<> 
    >>; 

有了這一點,你的sum定義,我可以這樣做:

std::function<int(FwdIter<int>, FwdIter<int>)> f = sum<int>{}; 
std::vector<int> v = {1, 2, 3, 4, 5}; 

std::cout << f(v.begin(), v.end()) << std::endl; // prints 15 

在你test<T>,你可能只是有一個std::function<T(FwdIter<T>, FwdIter<T>)>成員根據需要。

+0

哇!非常聰明。非常感謝你。我正在努力尋找替代解決方案(我將在下面將它編寫爲一篇新文章)。但我認爲你的答案更加優雅。 –

+0

我已經添加了替代解決方案作爲原始文章的更新。任何評論歡迎:) –

0

爲什麼不斯托克函子來代替,一樣的東西:

template <typename T> 
class test 
{ 
public: 
    template <typename I> 
    auto call(I first, I last) const 
    -> decltype(T()(first, last)) 
    { 
    return T()(first, last); 
    } 
}; 

並使用它:

test<sum<double>> t; 

Live example

+0

不幸的是,它不適用於我的情況,因爲我需要將函數作爲成員類存儲,因爲它在幾種方法中使用。 –

+0

@ seg.fault:您可以將'T'存儲爲成員(添加成員,構造函數,並由成員更改'T()')。 – Jarod42

+0

我不行。該功能可以在運行時變化。例如,'t.set(總和()); t.call(v.begin(),v.end()); t.set(意思是()); t.call(v.begin(); v.end());'。 –

1

我試着在另一種解決方案上工作。

基本上,用戶功能被包裹在一個固定夾持器中,該固定器夾持器將功能簽名固定到T(const std::vector<T>&)。至於@ Barry的解決方案(我接受的解決方案),這不需要外部庫。然而,由於在運行時構造矢量對象,因此它會遇到性能問題。此外,更重要的是,正如@Barry指出的,該解決方案對T(如T必須可複製)施加了人爲的要求。

這裏是:

template <typename T,typename F> 
class holder 
{ 
public: 
    holder(F f) : f_(f) { } 

    T operator()(const std::vector<T>& v) const 
    { 
     return f_(v.begin(), v.end()); 
    } 
private: 
    F f_; 
}; 

template <typename T> 
class test_v2 
{ 
public: 
    template <typename F> 
    void set(F f) 
    { 
    f_ = holder<T,F>(f); 
    } 
    template <typename I> 
    T call(I first, I last) const 
    { 
    return f_(std::vector<T>(first, last)); 
    } 
private: 
    std::function<T(const std::vector<T>&)> f_; 
};