Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 637
Alex ten Brink Avatar asked Jul 09 '18 12:07

Alex ten Brink


1 Answers

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.

like image 122
Oliv Avatar answered Nov 08 '22 13:11

Oliv