D. *_*riy 21 c++ templates language-lawyer template-meta-programming
我希望两个类中的类型声明相互依赖.这是第一个用clang和gcc编译的例子:
template <class Sum>
struct A
{
using X = char; // (1)
using Z = typename Sum::B::Y; // (2)
};
template <class Sum>
struct B
{
using Y = typename Sum::A::X;
};
struct AplusB
{
using A = ::A<AplusB>;
using B = ::B<AplusB>;
};
AplusB::A::Z z;
int main() {}
Run Code Online (Sandbox Code Playgroud)
然而,有一个有趣的时刻.如果你交换行(1)和(2),那么它将无法编译并出现错误:
错误:'A'中没有名为'X'的类型
这让我怀疑原始代码在C++标准意义上是否真的有效,或者它恰好编译?
这是第二个例子,它也利用了模板实例化的顺序:
template <class Sum>
struct A
{
using X = char;
using P = typename Sum::B::Q;
};
template <class Sum>
struct B
{
using Y = typename Sum::A::X;
using Q = int;
};
struct AplusB
{
using A = ::A<AplusB>;
using B = ::B<AplusB>;
};
AplusB::A::X z; // (1)
AplusB::B::Q t; // (2)
int main() {}
Run Code Online (Sandbox Code Playgroud)
这里如果你交换(1)和(2)它将无法编译错误:
错误:'B'中没有名为'Q'的类型
所以问题是:类定义的标准实际上是否允许这样依赖彼此?
正如另一个答案中所讨论的,CWG 287 的决议只是实施所遵循的事实上的方法,它要求被实例化的成员的“内联”PoI 之前的实体恰好在范围内。
因此,当交换行时,我们尝试访问尚未实例化的内容:
template <class Sum>
struct A
{
using X = char; // (#)
using P = typename Sum::B::Q; // (2.3), (1.2)
};
template <class Sum>
struct B
{
using Y = typename Sum::A::X; // (2.2), (1.3)
using Q = int; // (*)
};
struct AplusB
{
using A = ::A<AplusB>; // (1.1)
using B = ::B<AplusB>; // (2.1)
};
AplusB::B::Q t; // (2)
AplusB::A::X z; // (1) (INDEPENDENT example)
Run Code Online (Sandbox Code Playgroud)
序列 (2)、(2.1)、(2.2) 和 (2.3) 是引发实例化的顺序,有效 PoI 位于该声明之前。首先声明 (2),在 (2.3) 处,我们引用了 (*),它不在范围内。如果 (1) 先出现,那么在 (1.3) 处我们访问 (#),它确实在范围内。(在随后的 (2) 声明中, 的特化A已经被完全实例化,因此没有进一步的微妙之处。)
如果您在“递归”别名之前声明所有“基本情况”别名(这是第一个片段中的差异),那么无论哪种方式都可以正常工作。
| 归档时间: |
|
| 查看次数: |
574 次 |
| 最近记录: |