我试图编写一个通用函数来计算一定范围内的平均值。
template <typename Range, typename Ret, typename Func>
Ret average(Range range, Ret zero, Func extract) {
Ret sum = zero;
int numElements = 0;
for (const auto& elem : range) {
sum += extract(elem);
++numElements;
}
if (numElements > 0)
sum /= numElements;
return sum;
}
我遇到的问题是使用
/=
运算符,但为了更好地澄清此函数的参数,让我澄清一下:
-
Range range
是定义范围的任何对象
begin()
和
end()
成员函数。我可能需要补充一点
const&
避免不必要的复制。
-
Ret zero
定义计算平均值时使用的加法的中性元素。它可能只是一个标量,但也适用于向量或矩阵。
-
Func extract
是一个函数(通常作为lambda函数给出),它将范围中的元素转换为
Ret
我的平均值。在实践中,我使用它作为我迭代的大对象中特定字段的getter。
我可以把它定义为
std::function<Ret(decltype(*range.begin()))>
或者类似的东西,如果C++没有问题,这样就可以推断出类型。
我想
Ret
提供
一些
/=
运算符,上面的函数可以使用,但我不想要求它
int
明确地
例如,在我的用例中,
Ret
合作
float
-这给了我一个恼人的警告:
warning: 'argument': conversion from 'int' to 'float', possible loss of data
所以
我有什么选择可以使上述功能干净,并与任何合适的
operator/=
?
例如,我尝试推导运算符的右参数类型,并显式转换为:
template <typename Range, typename Ret, typename Func>
Ret average(Range range, Ret zero, Func extract) {
Ret sum = zero;
int numElements = 0;
for (const auto& elem : range) {
sum += extract(elem);
++numElements;
}
using F = std::remove_pointer<decltype(&Ret::operator/=)>;
if (numElements > 0)
sum /= static_cast<typename boost::function_traits<F>::arg1_type>(numElements);
return sum;
}
但是我得到了很多编译错误,这表明我不知道自己在做什么。首先是:
error: 'boost::detail::function_traits_helper<std::remove_pointer<SpecificTypeUsedAsRet &(__cdecl SpecificTypeUsedAsRet::* )(float)> *>': base class undefined
那可能是因为
boost::function_traits
不适用于成员函数,只适用于常规函数?
我还担心,在以下情况下,这种解决方案可能无法奏效:
-
这个
接线员/=
不是作为成员函数给出的,而是作为带有两个参数的正则函数给出的。
-
这个
接线员/=
相对于其右操作数重载。一
智力
可能只匹配其中一个重载-因此没有歧义,但是
decltype
不知道该承受哪种超负荷。
-
我宁愿不使用
boost
但要坚持由最新的C++标准提供的权力