10

Why is the 2nd assignment allowed, when the inferred return type is std::nullptr_t? With function pointers this is forbidden.

And why doesn't the 2nd lambda run?

#include <cstdio>
#include <functional>

int main()
{
    std::function<void* ()> f;

    f = []() -> void* {
        printf ("runs\n");
        return nullptr;
    };
    f();

    f = []() {
        printf ("doesn't run\n");
        return nullptr; // -> std::nullptr_t
    };
    f();

    return 0;
}
Valentin Milea
  • 3,186
  • 3
  • 28
  • 29

1 Answers1

14

std::function allows you to store anything, as long as the following holds for the signature you provided:

  • all argument types are implicitly convertible to the argument types of the stored callable entity, and
  • the return type of the stored callable entity is implicitly convertible to the return type of the signature

std::nullptr_t is implicitly convertible to any pointer type and yields the null pointer value of that pointer type.

Note that your code is not actually valid C++11, since you only have a return expr; and no trailing return type in the second lambda. As such no return type deduction will happen. GCC (and Clang, IIRC) implement this as an extension, since it's going to be part of the standard at some time.

Hari
  • 1,561
  • 4
  • 17
  • 26
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • And what about the second question, why isn't second lambda running? That indeed seems puzzling. – SomeWittyUsername Nov 03 '12 at 19:34
  • @icepack: It does, I'm currently investigating. MSVC yields the same behaviour. – Xeo Nov 03 '12 at 19:34
  • 1
    5.1.2(4) "If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type: — if the compound-statement is of the form { attribute-specifier-seqoptreturn expression ; } ...snip... — otherwise, *void*." – rici Nov 03 '12 at 19:34
  • So, since the return type is void, the lambda is not compatible with the std::function, which thus considers itself empty. – rici Nov 03 '12 at 19:35
  • @rici: If the `std::function` was empty, you'd get a `bad_function_call` exception. Also, you'd get an error before that if the return type deduced to `void` and you had a `return something;` in the body of the lambda. In OPs case, a GCC extension took care of that problem. Also, even if you specify the return type, the code is not run: http://liveworkspace.org/code/e4d8408d456c5227ce715a7740877fec. – Xeo Nov 03 '12 at 19:37
  • replacing the `return nullptr;` with `return (void*)nullptr;` results in second lambda running – SomeWittyUsername Nov 03 '12 at 19:38
  • @icepack: Well, in that case the return type will be deduced as `void*` and the second lambda will be equivalent to the first, signature-wise. I'm still investigating, but it seems Clang runs both fine... – Xeo Nov 03 '12 at 19:44
  • C++11 has return type deduction for lambdas, this is not an extension – Guillaume Racicot Aug 30 '23 at 23:32