TIL the following program is legal and whatnot:
#include <vector>
struct Bar;
struct Foo
{
using BarVec = std::vector<Bar>::size_type;
};
struct Bar {};
int main()
{
Foo f;
}
How? Bar
is an incomplete type so the compiler has no way of knowing what std::vector<Bar>
is, or that it contains a member size_type
, or that the member size_type
is a type.
The only explanation I can come up with is that any hypothetical specialisation would (presumably) have to already be in scope to cause size_type
to take on a meaning different from that given in the "base" template definition, and size_type
is not a dependent name (both factors contributing to the compiler's certainty).
What's the legal rationale here?
I think in practice this may work but from what I can tell this looks like undefined behavior. From the draft C++11 standard 17.6.4.8
[res.on.functions]:
In particular, the effects are undefined in the following cases:
[...]
- if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.
Although instantiating a template component does not seem like a well-defined term.
I came to this via LWG defect 611 which added:
unless specifically allowed for the component.
to the end of the bullet above so it now reads:
if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for the component.
as an exception for shared_ptr
since the above quote conflicted with this quote from 20.6.6.2
[util.smartptr.shared]:
The template parameter T of shared_ptr may be an incomplete type.
Also see N4371: Minimal incomplete type support for standard containers, revision 2.
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