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 typesArgTypes...
and return typeR
.20.9.11.2 Class template function [func.wrap.func]
2 A callable object
f
of typeF
is Callable for argument typesArgTypes
and return typeR
if the expressionINVOKE
(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)
asINVOKE
(f, t1, t2, ..., tN)
implicitly converted toR
.
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.