我正在尝试编写一个通用函数来计算特定范围内的平均值。
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
值。在实践中,我将它用作迭代的大对象中特定字段的吸气剂。
如果C ++在用这种方式推断类型时没有问题,我可能将其定义为std::function<Ret(decltype(*range.begin()))>
或类似的名称。
我假设Ret
提供了上述功能可以使用的 some /=
运算符,但我不想要求它采用int
例如,在我的用例中,Ret
与float
-s一起使用,这给了我一个烦人的警告:
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
不能用于成员函数,而只能用于常规函数吗?
我还担心在以下情况下该解决方案可能无法正常工作
:operator/=
不是作为成员函数给出的,而是作为具有两个参数的常规函数给出的。operator/=
的右操作数过载。 int
可能只匹配其中一个重载-因此没有歧义,但是decltype
不知道要承担哪个重载。boost
,而是坚持使用最新的C ++标准提供的功能答案 0 :(得分:0)
您可以简单地声明Ret numElements = 0;
而不是使其成为int
。如果它有/=
运算符,则可能有一个++
运算符;或者您也可以使用num_elements += 1
。