2013-07-06 56 views
0

對於下面的代碼來處理不同的迭代器值類型:如何使用相同的功能

template < class _InIt, 
      class _Ty, 
      class _Fn2 > inline 
_Ty accumulateSimplePtr(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func) 
{ 
    // return sum of _Val and all in [_First, _Last), using _Func 
    for (; _First != _Last; ++_First) 
    { 
     if (is_class<std::iterator_traits<_InIt>::value_type>::value) 
      _Val = _Func(_Val, (*_First)()); 
     else 
      _Val = _Func(_Val, *_First);//This line doesn't work... 
    } 
    return (_Val); 
} 

我想要的代碼工作既爲_InIt指向double,並指着一類。 如果指向一個類,我將使用(*_First)()來獲取數據(假設該類有operator(),返回double),否則我只需使用*_First來獲取數據。

有沒有什麼方法可以使用boost::is_class或其他任何方式來做到這一點?

回答

1

我不認爲這是一個好主意。我寧願寫兩個不同的功能來處理兩種不同類型的像這樣:

// Also, note, your function is very similar to 
// std::accumulate from numeric header 

std::vector<Foo> v1{3.14159, 1.77245385}; 
std::accumulate 
(
    v1.begin(), v1.end(), 0., 
    [] (double i, const Foo& f) { return i + f(); } 
); 

std::vector<double> v2{3.14159, 1.77245385}; 
std::accumulate(v2.begin(), v2.end(), 0.); 

但是,如果你不想這樣做,我建議寫一個函數包裝:

namespace detail 
{ 

template <class F, class V, class T> 
auto function_wrapper(F&& f, V&& v, T&& t) 
    -> typename std::enable_if 
     < 
      std::is_class<typename std::remove_reference<T>::type>::value, 
      typename std::remove_reference<V>::type 
     >::type 
{ 
    return std::forward<F>(f)(std::forward<V>(v), std::forward<T>(t)()); 
} 

template <class F, class V, class T> 
auto function_wrapper(F&& f, V&& v, T&& t) 
    -> typename std::enable_if 
     < 
      !std::is_class<typename std::remove_reference<T>::type>::value, 
      typename std::remove_reference<V>::type 
     >::type 
{ 
    return std::forward<F>(f)(std::forward<V>(v), std::forward<T>(t)); 
} 

} // namespace detail 

template < class _InIt, 
      class _Ty, 
      class _Fn2 > inline 
_Ty accumulateSimplePtr(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func) 
{ 
    for (; _First != _Last; ++_First) 
     _Val = detail::function_wrapper(_Func, _Val, *_First); 
    return (_Val); 
} 

class Foo 
{ 
public: 
    Foo(double d): _d(d) 
    { 

    } 

    double operator()() const 
    { 
     return _d; 
    } 

private: 
    double _d; 
}; 


int main() 
{ 
    auto f = [] (double a, double b) { return a + b; }; 

    std::vector<Foo> v1{3.14159, 1.77245385}; 
    std::cout << accumulateSimplePtr(v1.begin(), v1.end(), 0., f) << std::endl; 

    std::vector<double> v2{3.14159, 1.77245385}; 
    std::cout << accumulateSimplePtr(v2.begin(), v2.end(), 0., f) << std::endl; 

    return 0; 
} 
+0

謝謝,它工作得很好! – Michael

1

您可以使用std::enable_if,適用於 模板函數的返回類型,來指示編譯取決於VALUE_TYPE是否是類或 沒有,像這樣 不同的功能實例:

#include <type_traits> 
#include <iterator> 

// Compiler will choose this one when the value_type is a class 
template < class _InIt, 
      class _Ty, 
      class _Fn2 
> 
typename std::enable_if< 
    std::is_class< 
     typename std::iterator_traits<_InIt>::value_type 
    >::value, 
    _Ty 
>::type 
accumulateSimplePtr(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func) 
{ 
    // return sum of _Val and all in [_First, _Last), using _Func 
    for (; _First != _Last; ++_First) { 
     _Val = _Func(_Val, (*_First)()); 
    } 
    return (_Val); 
} 

// Compiler will choose this one when the value_type is not a class 
template < class _InIt, 
      class _Ty, 
      class _Fn2 
> 
typename std::enable_if< 
    !std::is_class< 
     typename std::iterator_traits<_InIt>::value_type 
    >::value, 
    _Ty 
>::type 
accumulateSimplePtr(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func) 
{ 
    // return sum of _Val and all in [_First, _Last), using _Func 
    for (; _First != _Last; ++_First) { 
     _Val = _Func(_Val, *_First); 
    } 
    return (_Val); 
} 

閱讀std::enable_ifhere

,你試圖做這不起作用的方式,因爲它需要 編譯器編譯兩個* is_a_class」和is_not_a_class分支 的if的,甚至儘管它們不能同時編譯。 std::enable_if導致 只能編譯正確的函數。

請注意,你不應該使用帶有下劃線 和大寫字母開頭的標識符作爲所有這些名稱均用於編譯器和 它的圖書館。見here

+0

謝謝你的解決方案 – Michael

相關問題