繁体   English   中英

std :: function隐式类型转换

[英]std::function implicit type conversion

使用g++ (Ubuntu 4.8.5-1ubuntu1) 4.8.5并使用g++ -std=c++11 -Wall -Wextra -Wconversion

不能按预期编译以下内容:

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;
};

如下所示,编译时带有-Wconversion的警告:

void foo(float t){}
int main() {
    foo(3.141592653589794626);
    return 0;   
}

但是,以下编译没有警告

#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;
}

显然,这是一些自动转换float<->double但是为什么在第三个示例而不是第一个示例中允许它? -Wconversion为什么不能抓住这个?

(例如,在使用纬度/经度时,精度的无形损失在许多地区都是一个问题)。

正如Elwin Arens指出的那样,问题在于std::function的内部工作中正在进行类型擦除。 有人可能认为一种快速的解决办法是将构造器参数中的类型更改为double ,但这并不能防止用户传入一个带float的函数。 例如,

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
}

编译文件,但给出了不希望的结果。 一种解决方法是使用模板构造函数和一些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
}

现在,如果传入与Bar::foo的签名不匹配的函数,它将无法编译。 复杂的是,如果更改,则必须确保func_type 匹配Bar::foo的签名。

这与性病功能::这样做的目的是为运行时多态性,因此它使用的类型擦除,这已经讨论过这里 这里这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM