I have been playing around with C++11 lately, and came up with the following sum function:
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;
}
The idea is that I can pass a lambda function and thus have a neat and readable function for mathematical sums. I then tried the following:
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;
}
I compiled this using g++ 4.6.3: g++ -Wall -pedantic -std=c++0x -o test main.cpp
and does not give any warning about the precision loss I remarked in the comment of the source code.
It's pretty much a given here that sum<int>
is a bad thing to do, but it might not be that obvious in more complex contexts. Should the compiler not notice that return value of my lambda function is double
and warn me that I am losing out on precision when casting to int
? Is there a specific reason it does not?
Seems entirely reasonable. You're telling the compiler not to bother with Template Argument Deduction (i.e. use sum<double>
) but instead tell it explicitly to use sum<int>
. That's as good as an explicit cast.
[Edit] What about
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;
}
VS11 does issue a warning:
Warning 1 warning C4189: 'n' : local variable is initialized but not referenced
Warning 2 warning C4244: '+=' : conversion from 'double' to 'int', possible loss of data
Edit, actually that warning is from using the code:
template <typename T,typename Func>
inline T sum(Func f, int initial, int end)
You get a different warning about the bad conversion if you use std::function<T (int)>
, so VS is still good on this issue. (IMO, you should generally take functors as a templated type rather than std::function)
Even clang with -Weverything doesn't issue a warning about this (Edit: although I can't test the std::function version with clang ATM). Seems like something that could be improved.
I do get this strange warning though:
ConsoleApplication1.cpp:15:51: warning: will never be executed [-Wunreachable-code]
auto n = sum<int>([&](int k) { return arr1[k]*arr2[k]; }, // Precision loss!
^~~~
If you unconstrain the functor and if you change the line retval += f(k);
to retval += T { f(k) };
in the following way:
// 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;
}
then instead of relying on the compiler's willingness to warn, you make it required to emit a diagnostic as a narrowing conversion is disallowed within list-initialization (i.e. initialization with braces).
I don't think there's a reliable way if you constrain the functor to an std::function<Sig>
. That depends solely on how the implementation wrote std::function
, when it issues warnings for narrowing conversions, and even whether it warns for its own code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With