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()>) { } };
| ^ ~~~~~~~~~~~~~~~~~~~~~
Let's 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.
in MSVC C++20 flag automatically adds /permissive- , it doesn't compile with C++17 and /permissive- non working godbolt demo
technically it shouldn't compile because this requires 2 implicit conversions, lambda -> std::function -> S
you need a constructor that can accept anything convertible to std::function<void()>
struct S {
S(std::function<void()>) { }
S(auto&& arg) requires requires {std::function<void()>{arg};} {}
};
godbolt demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With