静态引用强制强制模板实例化,其中不完整类型可以

时间:2018-07-09 12:42:37

标签: c++ templates language-lawyer incomplete-type

以下代码无法在gcc 7.3.0和clang 6.0.0上编译(但在MSVC下似乎可以正常编译):

p

我得到的错误是:

#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;
}

在这里自己尝试:https://godbolt.org/g/5AW37K

但是,如果我将第10行替换为

,它将编译
<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

就像@ Jarod42所述,如果删除Container的定义,它将再次编译:http://godbolt.org/g/ue9iwC看起来像gcc和clang,因此仅在定义了模板类的情况下实例化。

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

请注意,上面代码中的模式来自gcc的std :: is_constructible实现,当我尝试复制包含模板类的const ref且具有不完整类型参数的元组时,触发了错误是的,这实际上发生了。

2 个答案:

答案 0 :(得分:1)

根据标准隐式类模板实例化,仅当需要完整的对象时[temp.inst]/1

  

[...],类模板   当专门化是时,隐式实例化专门化   在需要完全定义的对象类型的上下文中引用   或类类型的完整性影响以下语言的语义时   该程序。

正如Jarod的评论中指出的那样,如果未提供container的定义,则与InCompleteType的完整性无关,Unintatiable是不完整的类型和代码编译。此外,此static_cast显然与对象的完成无关。所以我认为这是gcc和clang的编译器错误。

答案 1 :(得分:0)

如果不实例化模板化的类,就不会出错。

拥有

 using Uninstantiatable = IncompleteType;

表示您仅在IncompleteType上生成参考。在未定义类型上具有引用或指针是可以的,因为在这里编译器只需要为指针生成代码即可。但是,如果您实例化您的课程:

template<typename T>
struct Container {
    T value;
};

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

拥有

decltype(static_cast<Uninstantiatable const&>) 

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