c++ - std::function implicit type conversion -
using g++ (ubuntu 4.8.5-1ubuntu1) 4.8.5
, compiling g++ -std=c++11 -wall -wextra -wconversion
the following not compile expected:
template <typename t> struct foo { foo(t t) {} }; struct bar { bar(foo<float> foo) : foo(foo) {} //trying convert foo<float> foo<double> foo<double> foo; };
the following compiles warning -wconversion
, expected:
void foo(float t){} int main() { foo(3.141592653589794626); return 0; }
however, following compiles no warnings:
#include <functional> void foo(double t){} struct bar { bar(std::function<void(float)> foo) : foo(foo) {} //convert std::function<void(float)> std::function<void(double)> std::function<void(double)> foo; }; int main(){ bar bar(foo); //convert std::function<void(double)> std::function<void(float)> bar.foo(3.141592653589794626); //rounded to: 3.141592741012573 foo(3.141592653589794626); //not rounded: 3.141592653589794 return 0; }
clearly automatic conversion float<->double
why allowed in third example , not first? why -wconversion
not catch this?
(invisible loss of precision problem in number of areas, example when working latitude/longitude).
as elwin arens noted, problem type erasure going on in inner workings of std::function
. 1 might suppose quick fix change type in constructor argument double
, doesn't prevent user passing in function takes float
. example,
void foo(float t) { std::cout << std::setprecision(15) << std::fixed << t << std::endl; } struct bar { bar(std::function<void(double)> foo) : foo(foo) {} std::function<void(double)> foo; }; int main() { bar bar(foo); bar.foo(3.141592653589794626); //rounded to: 3.141592741012573 foo(3.141592653589794626); //not rounded: 3.141592653589794 }
compiles file, gives undesired result. 1 fix use template constructor , tmp.
void foo(double t) { std::cout << std::setprecision(15) << std::fixed << t << std::endl; } struct bar { using target_type = double; using func_type = void(*)(target_type); template <typename t, typename u = typename std::enable_if<std::is_same<t,func_type>::value,void>::type> bar(t foo) : foo(foo) {} std::function<void(target_type)> foo; }; int main() { bar bar(foo); bar.foo(3.141592653589794626); //rounded to: 3.141592741012573 foo(3.141592653589794626); //not rounded: 3.141592653589794 }
now fails compile if pass in function doesn't match signature of bar::foo
. complication have make sure func_type
also matches signature of bar::foo
if ever changes.
Comments
Post a Comment