#include <iostream>
template<typename T>
struct A{
template<typename U>
struct B{};
B<T> b; //#2
};
//#3
int main() {
A<int> a; // #1
}
考虑上面的代码,使用template-id A
温度点#4
对于类模板专用化、类成员模板专用化或类模板的类成员的专用化,如果专用化是隐式实例化的,因为它是从另一个模板专用化中引用的,如果引用专用化的上下文依赖于模板参数,并且如果在封闭模板实例化之前未实例化专用化, 实例化点紧接在封闭模板的实例化点之前。否则,此类专用化的实例化点紧接在引用专用化的命名空间范围声明或定义之前。
对于在<code>#1</code>中引用的专用化,该规则的“否则”部分将应用于它。这意味着,<code>A的实例化点
使用普通类更改示例:
struct Normal_A_Int{
struct Normal_B_Int{};
Normal_B_Int b;
};
int main(){
Normal_A_Int a;
}
这意味着,成员类
Normal_B_Int
的定义必须在封闭类的定义中,因为声明Normal_B_Intb
是一个完整的类类型。
那么,怎么可能让成员类< code>B的定义
好吧,我确实在你的第一个例子上运行了CppInsights:https://cppinsights.io/lnk?code=dGVtcGxhdGU8dHlwZW5hbWUgVD4Kc3RydWN0IEF7CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBVPgogICAgc3RydWN0IEJ7fTsKICAgIEI8VD4gYjsKfTsKCmludCBtYWluKCkgewogICAgQTxpbnQ IGE7Cn0KCgoK
您从temp.point/4中提供的报价正是这种情况:
template<typename T>
struct A {
template<typename U>
struct B { };
B<T> b;
};
// point-of-instantiation for A<int>::B<int>
// point-of-instantiation for A<int>
int main() {
A<int> a;
}
没什么律师可做的。标准说这些是实例化的点。类模板不是类,直觉不一定会延续。它们都有定义和实例化。
以外部类定义为例。如果它是一个类,则必须定义成员的类型。如果是类模板,则只能声明成员的类型。你可以降低B的定义:
template<typename T>
struct A {
template<typename U> struct B;
B<T> b;
};
template<typename T>
template<typename U>
struct A<T>::B { };
您无法对类执行此操作(定义中有一个“不完整”成员),但可以使用类模板执行此操作。
所以问题是,为什么模板的实例化点是A
也许直觉来自将定义和实例化点混为一谈:
那么,怎么可能让成员类B的定义在某个时候放在封闭类A的定义之前呢?
它不是。实例化点控制名称可见性。TU中到此为止的所有名称都可见。(这不是定义。)从这个角度来看,很明显
A
这条规则有两个有趣的方面。
一是模板可以专门化。因此,为了满足这一要求,当编译器实例化< code>A
第二个方面更有趣。您可以从普通类的直觉中期待
B的定义
template<typename T>
struct A {
using type = T;
template<typename U>
struct B { using type = typename A<U>::type; };
B<T> b;
};
可以吗?
如果< code >的实例化点
这是CWG287和P1787的领域。
CWG287建议实例化点相同(一个不在另一个之前)。此外,它还将补充:
如果隐式实例化的类模板专用化、类成员专用化或类模板的专用化引用了包含直接或间接导致实例化的专用化引用的类、类模板专用化、类成员专用化或类模板的专用化,则类引用的完整性和排序要求适用于专用化引用的上下文。
在我的示例中,
A
CWG287似乎旨在复制编译器已经做的事情。然而,CWG287自2001年以来一直开放。(另请参阅这个和这个。)
P1787似乎是针对C 23的,旨在重写许多微妙的语言。我认为其目的与CWG287类似。但要做到这一点,他们必须彻底重新定义名称查找,以至于我很难知道这一点
这里有一个最小的例子来说明我遇到的问题。 模板成员显式专用于基类中的。模板的代码是显式生成的,并在成员中调用。 我发现的第一个问题是: 该错误是由于在main中调用造成的。可以通过调用来避免这种情况。为什么在的实例中显然是不可见的?
还尝试在专门化的中进行模板方法专门化: 这一次它编译,但调用原始方法,即 解决方案
是否有人知道此显式特化是否有效: clang 主干 (12/3/2013) 给出以下错误: f:...\test.cpp:36:20: 错误: 从类 'O' 中出线定义 “Fun” 没有定义 1生成错误。 任何来自标准的支持参考来证明你的答案将不胜感激! 注意:我有点惊讶这是一个错误——我认为应该为任何以< code >开始实例化“Fun”的模板参数族选择专门化 这是一个叮当的错误还是我期望中的错
[dcl.spec.auto]/14国[强调我的]: 显式实例化声明不会导致使用占位符类型声明的实体的实例化,但也不会阻止根据需要对该实体进行实例化以确定其类型。[示例: -结束示例] 和[temp.explicat]/11声明[强调我的]: 现在,考虑我们是否在类模板中的friend声明中定义了friend函数: 如果在同一翻译单元中实例化了的多个专门化,则将违反[basic.def.odr]/
问题内容: 这是我的代码: 它运作良好。但是当我尝试添加这个 我遇到编译器错误:«int MyClass :: DoSomething()»的«>»令牌模板标识«DoSomething <0>»之前的无效显式专门化与任何模板声明都不匹配 我使用g ++ 4.6.1应该怎么做? 问题答案: 不幸的是,如果不对外部模板进行特殊化处理,就不能对作为类模板成员的模板进行特殊处理: C ++ 11 14.7
考虑上面的代码,在中,它是成员类模板成员的明确专门化定义。一些规则将适用于以下规定: 临时雇员爆炸。规格#5 显式特化类的成员不会从类模板的成员声明中隐式实例化;相反,如果需要定义,则应显式定义类模板特化的成员本身。在这种情况下,类模板显式特化的定义应在定义成员时处于范围内。显式特化类的定义与生成的特化的定义无关。也就是说,其成员不必与生成的特化的成员具有相同的名称、类型等。显式特化类模板的成员的
这有什么问题: 我在这里尝试过:用不同的编译器https://godbolt.org/z/NkL44s: x86-64 gcc 9.2:编译 x86-64 gcc(主干):失败 x86-64 clang 6.0.0:编译 x86-64 clang 7.0.0及更高版本:失败 x64 msvc v19.22:编译 x64 msvc v19.23(内部测试):失败 那么,为什么最近的编译器会拒绝这一点