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或任何其他方式来做到这一点?

4

2 回答 2

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;
}
于 2013-07-06T07:02:16.177 回答
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_if

您尝试执行此操作的方式不起作用,因为它需要编译器同时编译*is_a_class" 和is_not_a_class分支if,即使它们不能同时编译。std::enable_if只会编译正确的函数。

请注意,您不应该使用以下划线和大写字母开头的标识符,因为所有这些标识符都是为编译器及其库保留的。见这里

于 2013-07-06T07:06:30.830 回答