我想传递一个非捕获的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) {}
答案 0 :(得分:5)
<强> 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).
构造函数没有可行的重载。请参阅以下代码:
std::function
当您明确指定lambda的返回类型时,您更改lambda的调用运算符的返回类型(实际与其关联的闭包类型,请参见末尾的引号),因此可以进行转换。 / p> 另一方面,
std::function
没有这样的约束 - template <typename F>
std::function(F &&f);
的构造函数是模板化的,所以它可以采取任何可调用的:
INVOKE(f, std::forward<Args>(args)..., R)
...只要以下内容有效 2 :
INVOKE (f, declval<ArgTypes>()..., R)
1 N4594的标准报价,§5.1.5/ 7(重点是我的):
没有lambda-capture的非泛型lambda表达式的闭包类型有一个转换函数指向函数,C ++语言链接(7.5)具有相同的参数和返回类型作为 闭包类型的函数调用操作符。 [...] 子>
2 N4594的标准报价,§20.12.12.2/ 2:
类型F的可调用对象f对于参数类型ArgTypes是可调用的,如果被视为未评估操作数(第5节)的表达式
INVOKE (f, t1, t2, ..., tN)
形成良好,则返回类型R(20.12.2) 子>
...和§20.12.2(强调是我的,1.1到1.6是关于成员函数的指针(或类似),所以这里不相关):
1 定义
f(t1, t2, ..., tN)
如下:(1.x) - [...]
(1.7) -
INVOKE (f, t1, t2, ..., tN, R)
在所有其他情况下。2 如果R为cv void,则将
INVOKE (f, t1, t2, ..., tN)
定义为static_cast(INVOKE (f, t1, t2, ..., tN)
),否则{{1}} 隐式转换为R 强> 子>
答案 1 :(得分:1)
除了Holt的答案,还要涵盖您的第一个问题:您不一定必须明确指定返回类型作为尾随返回类型。但是,由于您创建的是unique_ptr<Derived>
,但需要unique_ptr<Base>
,因此您应该返回后者并在您的函数中执行转换。
所以,我相信,这就像
那样auto f2 = [](){ return std::unique_ptr<Base>{new Derived()}; };
也编译。