参考的静态强制转换强制模板实例化,其中不完整类型很好

Ale*_*ink 9 c++ templates language-lawyer incomplete-type

下面的代码无法在gcc 7.3.0和clang 6.0.0上编译(但似乎在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;
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是这样的:

<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
Run Code Online (Sandbox Code Playgroud)

亲自尝试一下:https://godbolt.org/g/5AW37K

但是,如果我替换第10行,它就会编译

using Uninstantiatable = IncompleteType;
Run Code Online (Sandbox Code Playgroud)

就像提到的@ Jarod42一样,如果删除Container的定义,它会再次编译:http://godbolt.org/g/ue9iwC因此,如果定义了gcc和clang,它只会实例化模板类.

在这两种情况下,我只是试图将const-ref复制到const-ref,所以我希望无论类型是什么都能工作,如果类型本身不完整,这确实有效.标准是否指定在此处触发模板实例化,或者gcc和clang在其行为中是否不正确?

请注意,上面代码中的模式取自gcc的std :: is_constructible实现,并且当我尝试复制包含带有不完整类型参数的模板化类的const ref的元组时触发了错误,所以是的,这个在实践中发生.

Kla*_*aus 0

如果您不实例化模板类,则不会出现错误。

拥有

 using Uninstantiatable = IncompleteType;
Run Code Online (Sandbox Code Playgroud)

意味着您仅生成IncompleteType. 在未定义类型上拥有引用或指针是可以的,因为编译器只需在此处为指针生成代码。但是如果你实例化你的类:

template<typename T>
struct Container {
    T value;
};
Run Code Online (Sandbox Code Playgroud)

这里您需要 T 的定义,它不是指针或引用,而是类型本身,此处未定义。因此编译器无法生成实例,因为它对此一无所知。

拥有

decltype(static_cast<Uninstantiatable const&>) 
Run Code Online (Sandbox Code Playgroud)

意味着您实例化了模板,这会导致错误。它与您只需要该语句中的引用无关。它与生成模板本身的实例有关,这是无法完成的,因为如上所述,那里的“T”是未知的。

  • 但是,如果删除“Container”定义,它会[编译](https://godbolt.org/g/ue9iwC),那么为什么在提供定义时会实例化模板呢? (2认同)