[英]std::function implicit type conversion
Using g++ (Ubuntu 4.8.5-1ubuntu1) 4.8.5
and compiling with g++ -std=c++11 -Wall -Wextra -Wconversion
使用
g++ (Ubuntu 4.8.5-1ubuntu1) 4.8.5
并使用g++ -std=c++11 -Wall -Wextra -Wconversion
The following does not compile which is as expected: 不能按预期编译以下内容:
template <typename T>
struct Foo {
Foo(T t) {}
};
struct Bar {
Bar(Foo<float> foo) : foo(foo) {} //Trying to convert Foo<float> to Foo<double>
Foo<double> foo;
};
The following compiles with a warning from -Wconversion
, as expected: 如下所示,编译时带有
-Wconversion
的警告:
void foo(float t){}
int main() {
foo(3.141592653589794626);
return 0;
}
However, the following compiles with no warnings : 但是,以下编译没有警告 :
#include <functional>
void foo(double t){}
struct Bar {
Bar(std::function<void(float)> foo) : foo(foo) {} //Convert std::function<void(float)> to std::function<void(double)>
std::function<void(double)> foo;
};
int main(){
Bar bar(foo); //Convert std::function<void(double)> to std::function<void(float)>
bar.foo(3.141592653589794626); //Rounded to: 3.141592741012573
foo(3.141592653589794626); //Not rounded: 3.141592653589794
return 0;
}
Clearly this is some automatic conversion float<->double
but why is it allowed in the third example and not the first? 显然,这是一些自动转换
float<->double
但是为什么在第三个示例而不是第一个示例中允许它? Why does -Wconversion
not catch this? -Wconversion
为什么不能抓住这个?
(Invisible loss of precision is a problem in a number of areas, for example when working with latitude/longitude). (例如,在使用纬度/经度时,精度的无形损失在许多地区都是一个问题)。
As Elwin Arens noted, the problem is with the type erasure going on in the inner workings of std::function
. 正如Elwin Arens指出的那样,问题在于
std::function
的内部工作中正在进行类型擦除。 One might suppose that a quick fix would be to change the type in the constructor argument to double
, but that doesn't prevent the user from passing in a function that takes a float
. 有人可能认为一种快速的解决办法是将构造器参数中的类型更改为
double
,但这并不能防止用户传入一个带float
的函数。 For 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, but gives the undesired result. 编译文件,但给出了不希望的结果。 One fix it to use a template constructor and some TMP.
一种解决方法是使用模板构造函数和一些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 it fails to compile if you pass in a function that doesn't match the signature of Bar::foo
. 现在,如果传入与
Bar::foo
的签名不匹配的函数,它将无法编译。 The complication is that you have to make sure that func_type
also matches the signature of Bar::foo
if ever it changes. 复杂的是,如果更改,则必须确保
func_type
也匹配Bar::foo
的签名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.