我最近一直在玩C ++ 11,并提出了以下求和函数:
template <typename T>
inline T sum(const std::function<T (int)> &f, int initial, int end)
{
T retval = 0;
for(int k = initial; k <= end; k++) {
retval += f(k);
}
return retval;
}
我的想法是,我可以传递一个lambda函数,因此对数学和有一个整洁可读的函数。然后我尝试了以下内容:
int main()
{
std::array<double, 2> arr1 = {{ 0.5, 1.5 }},
arr2 = {{ 1.5, -0.5 }};
auto n = sum<int>([&](int k) { return arr1[k]*arr2[k]; }, // Precision loss!
0, 1);
return 0;
}
我使用g ++ 4.6.3编译了这个:g++ -Wall -pedantic -std=c++0x -o test main.cpp
并且没有对我在源代码的注释中提到的精度损失发出任何警告。
这里给出的sum<int>
是一件坏事,但在更复杂的情况下可能并不那么明显。编译器是否应该注意到我的lambda函数的返回值是double
,并警告我在转换为int
时我的精度会丢失?它有没有特定的原因?
答案 0 :(得分:5)
似乎完全合理。您告诉编译器不要打扰模板参数扣除(即使用sum<double>
),而是明确告诉它使用sum<int>
。这和明确的演员一样好。
[编辑]
怎么样?template <typename F>
auto sum(F const& f, int initial, int end) -> decltype(f(initial))
{
auto retval = f(initial++);
while(initial <= end) {
retval += f(initial++);
}
return retval;
}
答案 1 :(得分:2)
VS11会发出警告:
警告1警告C4189:'n':局部变量已初始化但未引用 警告2警告C4244:'+ =':从'double'转换为'int',可能会丢失数据
编辑,实际上该警告来自使用代码:
template <typename T,typename Func>
inline T sum(Func f, int initial, int end)
如果您使用std::function<T (int)>
,则会收到有关错误转化的其他警告,因此VS在这个问题上仍然很好。 (IMO,你通常应该将仿函数作为模板类型而不是std :: function)
甚至叮叮当当 - 我们都没有发出关于此的警告(编辑:虽然我无法用clang ATM测试std :: function版本)。似乎可以改进的东西。
我确实得到了这个奇怪的警告:
ConsoleApplication1.cpp:15:51: warning: will never be executed [-Wunreachable-code]
auto n = sum<int>([&](int k) { return arr1[k]*arr2[k]; }, // Precision loss!
^~~~
答案 2 :(得分:1)
如果您取消了仿函数,并且您将行retval += f(k);
更改为retval += T { f(k) };
,请按以下方式进行:
// Machinery to allow caller to indifferently use
// sum(f, i, j) and sum<R>(f, i, j)
struct deduced {};
template<
typename Request = deduced
, typename Functor
, typename Ret = typename std::conditional<
std::is_same<Request, deduced>::value
, typename std::result_of<Functor&(int)>::type
, Request
>::type
>
inline Ret sum(Functor f, int initial, int end)
{
Ret retval = 0;
for(int k = initial; k <= end; k++) {
retval += Ret { f(k) };
}
return retval;
}
然后不依赖于编译器的警告意愿,而是让 required 发出诊断,因为在列表初始化(即使用大括号初始化)中不允许缩小转换。
如果您将仿函数约束为std::function<Sig>
,我认为没有可靠的方法。这完全取决于实现如何编写std::function
,何时发出缩小转换的警告,甚至是否警告自己的代码。