Reputation: 899
The following bit of code fails to compile on gcc 7.3.0 and clang 6.0.0 (but seems to compile fine under MSVC):
#include <utility>
struct IncompleteType;
template<typename T>
struct Container {
T value;
};
using Uninstantiatable = Container<IncompleteType>;
auto foo() -> decltype(static_cast<Uninstantiatable const&>(std::declval<Uninstantiatable const&>())) {
throw 1;
}
The error I get is this:
<source>:7:7: error: field has incomplete type 'IncompleteType'
T value;
^
<source>:12:24: note: in instantiation of template class 'Container<IncompleteType>' requested here
auto foo() -> decltype(static_cast<Uninstantiatable const&>(std::declval<Uninstantiatable const&>())) {
^
<source>:3:8: note: forward declaration of 'IncompleteType'
struct IncompleteType;
^
1 error generated.
Compiler returned: 1
Try it yourself here: https://godbolt.org/g/5AW37K
However, it compiles if I replace line 10 by
using Uninstantiatable = IncompleteType;
Like @Jarod42 mentioned, it compiles again if you remove the definition of Container: http://godbolt.org/g/ue9iwC It looks like gcc and clang therefore only instantiate the template class if it is defined.
In both cases, I'm simply trying to copy a const-ref to a const-ref, so I expect that to work regardless of what the type is, and this indeed works if the type itself is incomplete. Does the standard specify that a template instantiation is triggered here, or are gcc and clang incorrect in their behavior?
Note that the pattern in the code above is taken from the std::is_constructible implementation of gcc, and the error was triggered when I tried to copy a tuple containg a const ref of a templated class with an incomplete type parameter, so yes, this happens in practice.
Upvotes: 9
Views: 520
Reputation: 18051
According to the standard implicit class template instantiation should only be performed when a complete object is required [temp.inst]/1:
[...], the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.
As pointed out in Jarod's comment, if a definition for container
is not provided, Unintatiable is, independently of the completeness of InCompleteType
, an incomplete type and the code compile. Moreover this static_cast is obviously independent of the completness of the object. So I think this is a compiler bug of gcc and clang.
Upvotes: 1
Reputation: 25623
If you don't instantiate your templated class, you can't get an error.
Having
using Uninstantiatable = IncompleteType;
means that you generate only a reference on the IncompleteType
. Having a reference or a pointer on undefined types is ok, as the compiler only has to genrate code for a pointer here. But if you instantiate your class:
template<typename T>
struct Container {
T value;
};
Here you need the definition of T which is not a pointer or reference but the type itself which is here undefined. So the compiler can't generate a instance because it did not know anything about.
Having
decltype(static_cast<Uninstantiatable const&>)
means that you get your template instantiated which results in the error. It has nothing todo with the point that you only need a reference in that statement. It has to do with generating the instance of the template itself which ca't be done because the "T" there is not known as described above.
Upvotes: 0