Alex ten Brink
Alex ten Brink

Reputation: 899

Static cast of reference forces template instantiation where incomplete type is fine

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

Answers (2)

Oliv
Oliv

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

Klaus
Klaus

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

Related Questions