I want to pass a non-capturing lambda, which returns a
std::unique_ptr<Derived>, as a function pointer of type std::unique_ptr<Base>(*)().
However, this only works if I explicitly state the return type of the lambda as std::unique_ptr<Base>.
- Why do I have explicitly state the return type?
- Why does it work for a
std::functionwithout this extra return type?
#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 error:
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) {}
std::add_pointer_t<std::unique_ptr<Base>>;be a pointer to aunique_ptr<base>? See coliru.stacked-crooked.com/a/5a1c461bfb6199a8 I may be no expert here but I can guess the compiler has a problem converting aunique_ptr<derrived>to a pointer to aunique_ptr<base>while converting aunique_ptr<base>to a pointer tounique_ptr<base>it can somehow do implicitlystd::add_pointer_t<std::unique_ptr<Base>()>;please note the( )at the end