gpt4 book ai didi

c++ - std::function 是否允许在其返回类型中从引用到拷贝进行隐式转换?

转载 作者:IT老高 更新时间:2023-10-28 23:20:33 27 4
gpt4 key购买 nike

在下面截取的代码中,编译器将按复制返回的函数指针静默转换为按常量引用返回的 std::function。当调用 std::function 实例时,会返回对拷贝的引用并且应用程序崩溃(大部分时间;)。

通过比较,普通函数指针不允许这种隐式转换,所以我想知道我是否应该向编译器供应商提示(在这种情况下是 gcc 4.8),或者这种行为是标准规定的?

#include <iostream>
#include <functional>

typedef std::function<const std::string&(const std::string& x)> F;

std::string bad(const std::string& x) { return x; }
const std::string& good(const std::string& x) { return x; }

typedef const std::string& (*FP)(const std::string&);

int main(int, char**) {
std::cout << F(&good)("hello") << std::endl;
std::cout << F(&bad)("hello") << std::endl;

FP a = &good;
// FP b = &bad; Not allowed!

return 0;
}

附:这是现实世界问题的简化版本,其中 bad 实际上是一个返回某种类型成员的 lambda:

typedef std::function<const std::string&(const X& x)> F;
F f = [](const X& x) { return x->member(); };

我们花了一段时间才弄清楚这个 lambda 的返回类型被推导出为 std::string,而不是 const std::string&,并且这个导致崩溃。

最佳答案

这看起来像是一种极端情况。 §2.8.11.2.1/7 中的构造函数定义说:

Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R. [...]

§2.8.11.2/2 说:

A callable object f of type F is Callable for argument types ArgTypes and return type R if the expres- sion INVOKE (f, declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well formed (20.8.2).

最后 §20.8.2/2 说:

Define INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN) implicitly converted to R.

显然 T隐式转换为 T const &因此,在没有进一步限制的情况下,应该允许 构造函数。

然而调用这样的函数需要返回一个临时的引用,该临时的生命在引用被返回之前就结束了,这是未定义的行为。当某些事情是未定义的行为时,实现可以随心所欲。不幸的是,未定义的行为只发生在调用时,所以它仍然不严格符合在构造时检测它。

因为调用它是对象的唯一用途,所以如果禁止它会更好。所以这应该被认为是规范中的缺陷。

在任何情况下,我都建议将它放在适当的 gcc 邮件列表中。在这种情况下,维护者愿意稍微偏离规范,或者至少他们可以向 C++ 委员会提出或帮助您提出问题,因为他们经常与它合作。

关于c++ - std::function 是否允许在其返回类型中从引用到拷贝进行隐式转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23284971/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com