以下代码无法在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且具有不完整类型参数的元组时,触发了错误是的,这实际上发生了。
答案 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”未知,因此无法完成。