c++

Why can't I convert a lambda to a type constructed from std::function?


Why doesn't this code compile?

#include <functional>

struct S { S(std::function<void()>) { } };

int main()
{
    S a([]() {});   // compiles
    S b = []() {};  // doesn't compile (except pre-C++20 on MSVC!)
}

Clang's error:

error: no viable conversion from '(lambda at <source>:6:8)' to 'S'
      |         S b = []() {};  // doesn't compile (except pre-C++20 on MSVC!)
      |           ^   ~~~~~~~
note: candidate constructor not viable: no known conversion from '(lambda at <source>:6:8)' to 'std::function<void ()>' for 1st argument
      | struct S { S(std::function<void()>) { } };
      |            ^ ~~~~~~~~~~~~~~~~~~~~~

Solution

  • Lets put std::function and lambdas aside, because the issue is more general, and look at a simpler example:

    struct A {};
    
    struct B {
        B(A) {}
    };
    
    struct C {
        C(B) {}
    };
    
    int main() {
        C c1(A{});      // I
        C c2 = A{};     // II
    }
    

    I is ok but II fails with:

    <source>:15:7: error: no viable conversion from 'A' to 'C'
    

    (Full error here: https://godbolt.org/z/GYbezWEG5)

    The reason is that only a single user provided conversion is taken into account.

    C c1(A{}) requires to convert A to B to call the constructor of C. This is ok.

    C c2 = A{}; on the other hand would require to first convert the A to B and then B to C. This is not ok.

    For more details I refer you to cppreference.