以下代码:
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
的{{1}},也适用于指向类。
如果指向一个类,我将使用double
来获取数据(假设类具有返回(*_First)()
的operator()),否则我只是使用double
来获取数据。 / p>
有没有办法使用*_First
或其他任何方式来执行此操作?
答案 0 :(得分: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;
}
答案 1 :(得分: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
here
您尝试这样做的方式不起作用,因为它需要
编译器编译 * is_a_class“和 is_not_a_class 分支
虽然他们不能同时编译,但是if
。 std::enable_if
导致
只编译正确的函数。
请注意,您不应使用以下划线开头的标识符 和大写字母作为所有这些标识符保留给编译器和 它的图书馆。请参阅here。