Why assignment to std::function<X()> doesn't compile when it is a member of class X?
c++, c++11, lambda, std-function
Solution
This was PR60594, which got fixed in GCC 4.8.3. The comments on that bug point out why it is valid: although the standard requires template arguments for standard library templates to be a complete type (with some exceptions), `X()` is a complete type even if `X` is not.
There are several members of `std::function<X()>` that do implicitly require `X` to be a complete type. The template constructor you're using is one of them: it requires the return type of your lambda to be implicitly convertible to `X`, but whether `X` is convertible to itself depends on whether `X` is a complete type: if it's incomplete, the compiler can't rule out the possibility that it is an uncopyable unmovable type.
This requirement follows from:
20.9.11.2.1 function construct/copy/destroy [func.wrap.func.con]
8 Remarks: These constructors shall not participate in overload resolution unless `f` is Callable (20.9.11.2) for argument types `ArgTypes...` and return type `R`.
20.9.11.2 Class template function [func.wrap.func]
2 A callable object `f` of type `F` is Callable for argument types `ArgTypes` and return type `R` if the expression `INVOKE``(f, declval<ArgTypes>()..., R)`, considered as an unevaluated operand (Clause 5), is well formed (20.9.2).
20.9.2 Requirements [func.require]
2 Define `INVOKE``(f, t1, t2, ..., tN, R)` as `INVOKE``(f, t1, t2, ..., tN)` implicitly converted to `R`.
Several other members of `std::function` also require `X` to be a complete type.
You're only using that constructor after type `X` has already completed, though, so there's no problem: at that point, `X` certainly can be implicitly converted to `X`.
The problem was that `std::function` was performing checks that depend on `X` being a complete type, in a context where the standard doesn't support performing such checks, and this did not account for the possibility that `X` would become a complete type after the instantiation of `std::function<X()>` had already completed.
Problem
The following code doesn't compile: ``` #include <functional> struct X { std::function<X()> _gen; }; int main() { X x; x._gen = [] { return X(); }; //this line is causing problem! } ``` I don't understand why assignment to `x._gen` is causing problem. Both gcc and clang are giving similar error messages. Could anyone please explain it? Compiler error messages GCC's error: ``` In file included from main.cpp:1:0: /usr/include/c++/4.8/functional: In instantiation of ‘std::function<_Res(_ArgTypes ...)>::_Requires<std::function<_Res(_ArgTypes ...)>::_CheckResult<std::function<_Res(_ArgTypes ...)>::_Invoke<_Functor>, _Res>, std::function<_Res(_ArgTypes ...)>&> std::function<_Res(_ArgTypes ...)>::operator=(_Functor&&) [with _Functor = main()::__lambda0; _Res = X; _ArgTypes = {}; std::function<_Res(_ArgTypes ...)>::_Requires<std::function<_Res(_ArgTypes ...)>::_CheckResult<std::function<_Res(_ArgTypes ...)>::_Invoke<_Functor>, _Res>, std::function<_Res(_ArgTypes ...)>&> = std::function<X()>&]’: main.cpp:11:12: required from here /usr/include/c++/4.8/functional:2333:4: error: no matching function for call to ‘std::function<X()>::function(main()::__lambda0)’ function(std::forward<_Functor>(__f)).swap(*this); ^ /usr/include/c++/4.8/functional:2333:4: note: candidates are: /usr/include/c++/4.8/functional:2255:2: note: template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor) function(_Functor); ^ /usr/include/c++/4.8/functional:2255:2: note: template argument deduction/substitution failed: /usr/include/c++/4.8/functional:2230:7: note: std::function<_Res(_ArgTypes ...)>::function(std::function<_Res(_ArgTypes ...)>&&) [with _Res = X; _ArgTypes = {}] function(function&& __x) : _Function_base() ^ /usr/include/c++/4.8/functional:2230:7: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘std::function<X()>&&’ /usr/include/c++/4.8/functional:2433:5: note: std::function<_Res(_ArgTypes ...)>::function(const std::function<_Res(_ArgTypes ...)>&) [with _Res = X; _ArgTypes = {}] function<_Res(_ArgTypes...)>:: ^ /usr/include/c++/4.8/functional:2433:5: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘const std::function<X()>&’ /usr/include/c++/4.8/functional:2210:7: note: std::function<_Res(_ArgTypes ...)>::function(std::nullptr_t) [with _Res = X; _ArgTypes = {}; std::nullptr_t = std::nullptr_t] function(nullptr_t) noexcept ^ /usr/include/c++/4.8/functional:2210:7: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘std::nullptr_t’ /usr/include/c++/4.8/functional:2203:7: note: std::function<_Res(_ArgTypes ...)>::function() [with _Res = X; _ArgTypes = {}] function() noexcept ^ /usr/include/c++/4.8/functional:2203:7: note: candidate expects 0 arguments, 1 provided ``` Likewise, Clang throws this: ``` main.cpp:11:12: error: no viable overloaded '=' x._gen = [] { return X(); }; ~~~~~~ ^ ~~~~~~~~~~~~~~~~~~ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2270:7: note: candidate function not viable: no known conversion from '<lambda at main.cpp:11:14>' to 'const std::function<X ()>' for 1st argument operator=(const function& __x) ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2288:7: note: candidate function not viable: no known conversion from '<lambda at main.cpp:11:14>' to 'std::function<X ()>' for 1st argument operator=(function&& __x) ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2302:7: note: candidate function not viable: no known conversion from '<lambda at main.cpp:11:14>' to 'nullptr_t' for 1st argument operator=(nullptr_t) ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2192:39: note: candidate template ignored: disabled by 'enable_if' [with _Functor = <lambda at main.cpp:11:14>] using _Requires = typename enable_if<_Cond::value, _Tp>::type; ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2340:2: note: candidate template ignored: could not match 'reference_wrapper<type-parameter-0-0>' against '<lambda at main.cpp:11:14>' operator=(reference_wrapper<_Functor> __f) noexcept ^ ```