简体   繁体   English

std :: function是否允许在其返回类型中从引用隐式转换为复制?

[英]Does std::function allow an implicit cast from reference to copy in its return type?

In the code snipped below, the compiler silently casts the return-by-copy function pointer into a return-by-const-reference std::function. 在下面的代码中,编译器以静默方式将return-by-copy函数指针强制转换为const-by-const-reference std :: function。 When the std::function instance is called, a reference to the copy is returned and the application crashes (most of the time ;). 调用std :: function实例时,将返回对副本的引用,并且应用程序崩溃(大多数情况下;)。

By the way of comparison, ordinary function pointers don't allow this implicit cast, so I wonder if I should go off complaining to the compiler vendor (gcc 4.8 in this case), or is this behaviour mandated by the standard? 通过比较的方式,普通函数指针不允许这种隐式转换,所以我想知道我是否应该向编译器供应商抱怨(在这种情况下是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;
}

PS This is a simplified version of a real world problem, where bad was actually a lambda returning a member of some type: PS这是现实世界问题的简化版本,其中bad实际上是lambda返回某种类型的成员:

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

It took us a while to figure out that the return type of this lambda was deduced to std::string , not const std::string& , and that this was causing a crash. 我们花了一段时间才弄清楚这个lambda的返回类型被推导为std::string ,而不是const std::string& ,这导致了崩溃。

This looks like a kind of corner case. 这看起来像一种角落的情况。 The constructor definition in §2.8.11.2.1/7 says: §2.8.11.2.1/ 7中的构造函数定义说:

Requires: F shall be CopyConstructible . 要求: F应为CopyConstructible f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R. [...] 对于参数类型ArgTypes, f应为Callable(20.8.11.2)并返回类型R. [...]

§2.8.11.2/2 says: §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). 类型F可调用对象f对于参数类型ArgTypes是Callable,如果表达式INVOKE (f, declval<ArgTypes>()..., R)被认为是未评估的操作数(第5条),则返回类型R形成良好(20.8.2)。

and last §20.8.2/2 says: 最后§20.8.2/ 2说:

Define INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN) implicitly converted to R. 将INVOKE(f,t1,t2,...,tN,R)定义为隐式转换为R的INVOKE(f,t1,t2,...,tN)。

Obviously T implicitly converts to T const & and so in absence of further restriction, the constructor should be allowed. 显然, T隐式转换为T const & ,因此在没有进一步限制的情况下, 应该允许构造函数。

However calling such function involves taking returning reference to a temporary whose life ends before the reference is even returned, which is Undefined Behaviour. 但是,调用此函数涉及返回对临时引用的临时引用,该引用甚至在返回引用之前结束,这是未定义的行为。 And when something is Undefined Behaviour, the implementation may do whatever it pleases. 当某些东西是未定义的行为时,实现可能会做任何事情。 Unfortunately the undefined behaviour only happens at invoking, so it's still not strictly conforming to detect it at construction time. 遗憾的是,未定义的行为仅在调用时发生,因此它仍然不严格符合在构造时检测它。

Because calling it is the only use of the object, it would be better, if it was prohibited. 因为调用它是对象的唯一用途,所以如果被禁止则会更好。 So this should be considered defect in the specification. 因此,这应该被认为是规范中的缺陷。

In any case, I'd recommend bringing it up on appropriate gcc mailing list. 无论如何,我建议在适当的gcc邮件列表上提出它。 The maintainers be willing to diverge from the specification slightly in case like this or at least they could raise or help you raise the issue with the C++ committee as they work with it regularly. 在这种情况下,维护者愿意稍微偏离规范,或者至少他们可以提出或帮助你向C ++委员会提出问题,因为他们经常使用它。

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

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