繁体   English   中英

传递lambda,它返回多态unique_ptr,作为函数指针

[英]Passing lambda, which returns polymorphic unique_ptr, as function pointer

我想传递一个非捕获的lambda,它返回一个std::unique_ptr<Derived> ,作为std::unique_ptr<Base>(*)()类型的函数指针。

但是,这只有在我明确声明lambda的返回类型为std::unique_ptr<Base>时才有效。

  • 为什么我明确说明了返回类型?
  • 为什么没有这个额外的返回类型它适用于std::function

#include <functional>
#include <memory>

struct Base{virtual ~Base()=default;};
struct Derived : Base{};

struct FailsForF2
{
   using Function = std::add_pointer_t<std::unique_ptr<Base>()>;
   FailsForF2(Function f) {}
};

struct Works
{
   using Function = std::function<std::unique_ptr<Base>()>;
   Works(Function f) {}
};


std::unique_ptr<Derived> fun() {return std::make_unique<Derived>();} 

int main()
{

   auto f1 = [](){return std::make_unique<Base>();};
   auto f2 = [](){return std::make_unique<Derived>();};
   auto f3 = []()->std::unique_ptr<Base>{return std::make_unique<Derived>();};

   Works x1(f1);
   Works x2(f2);
   Works x3(f3);

   FailsForF2 x4(f1);
   FailsForF2 x5(f2);
   FailsForF2 x6(f3);
}

gcc错误

main.cpp: In function 'int main()':

main.cpp:34:20: error: invalid user-defined conversion from 'main()::<lambda()>' to 'FailsForF2::Function {aka std::unique_ptr<Base> (*)()}' [-fpermissive]

    FailsForF2 x5(f2);

                    ^

main.cpp:26:17: note: candidate is: main()::<lambda()>::operator std::_MakeUniq<Derived>::__single_object (*)()() const <near match>

    auto f2 = [](){return std::make_unique<Derived>();};

                 ^

main.cpp:26:17: note:   no known conversion from 'std::_MakeUniq<Derived>::__single_object (*)() {aka std::unique_ptr<Derived> (*)()}' to 'FailsForF2::Function {aka std::unique_ptr<Base> (*)()}'

main.cpp:10:4: note:   initializing argument 1 of 'FailsForF2::FailsForF2(FailsForF2::Function)'

    FailsForF2(Function f) {}

实例

TL; DR;

  • FailsForF2失败,因为std::unique_ptr<Derived> (*) ()不能隐式转换为std::unique_ptr<Base> (*) () ;
  • Works工作正常,因为std::unique_ptr<Derived>可以隐式转换为std::unique_ptr<Base> (参见末尾的标准引号)。

lambda可以隐式转换为具有相同返回类型和参数1的函数指针,因此您的三个lambdas可以分别转换为:

std::unique_ptr<Base> (*) ()
std::unique_ptr<Derived> (*) ()
std::unique_ptr<Base> (*) ()

由于std::unique_ptr<Derived> (*) ()与(并且不能转换为) std::unique_ptr<Base> (*) () ,因此FailsForF2构造函数没有可行的重载。 请参阅以下代码:

std::unique_ptr<Derived> (*pfd) () = f2; // Compiles.
std::unique_ptr<Base> (*pfb) () = pfd;   // Does not compile (invalid conversion).

当您明确指定lambda的返回类型时,您可以更改lambda的调用运算符的返回类型(实际与其关联的闭包类型,请参见末尾的引号),因此可以进行转换。


另一方面, std::function没有这样的约束 - std::function的构造std::function是模板化的,所以它可以采用任何可调用的:

template <typename F>
std::function(F &&f);

......只要以下内容有效2

INVOKE(f, std::forward<Args>(args)..., R)

1 N4594的标准报价,§5.1.5/ 7(重点是我的):

没有lambda-capture的非泛型lambda表达式的闭包类型有一个转换函数指向函数,C ++语言链接(7.5)具有闭包类型的函数调用操作符相同的参数和返回类型 [...]

2 N4594的标准报价,§20.12.12.2/ 2:

如果表达式INVOKE (f, declval<ArgTypes>()..., R)被视为未评估的操作数(第5条),则F类型的可调用对象f可用于参数类型ArgTypes并返回类型R (20.12.2)。

...和§20.12.2(强调是我的,1.1到1.6是关于成员函数的指针(或类似),因此这里不相关):

1定义INVOKE (f, t1, t2, ..., tN) ,如下所示:

(1.x) - [...]

(1.7) - f(t1, t2, ..., tN)在所有其他情况下。

2如果R为cv void, INVOKE (f, t1, t2, ..., tN) INVOKE (f, t1, t2, ..., tN) INVOKE (f, t1, t2, ..., tN, R)为static_cast( INVOKE (f, t1, t2, ..., tN) ),否则为INVOKE (f, t1, t2, ..., tN) 隐式转换为R.

除了Holt的答案,还要涵盖您的第一个问题:您不一定必须明确指定返回类型作为尾随返回类型。 但是,由于您正在创建unique_ptr<Derived> ,但想要unique_ptr<Base> ,您应该返回后者并在您的函数中执行转换。

所以,我相信,这是有道理的

auto f2 = [](){ return std::unique_ptr<Base>{new Derived()}; };

这也编译。

暂无
暂无

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

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