【问题标题】:Curiously mutually recurring class definitions奇怪地相互重复的类定义
【发布时间】:2018-06-22 00:06:09
【问题描述】:

我希望两个类中的类型声明相互依赖。这是第一个使用 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() {}

然而,有一个有趣的时刻。如果将第 (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() {}

这里如果你交换 (1) 和 (2) 它将无法编译并出现错误:

错误:“B”中没有名为“Q”的类型

所以问题是:标准是否允许类定义像这样相互依赖?

【问题讨论】:

  • AplusB 在专业化 A&lt;AplusB&gt;B&lt;AplusB&gt; 中不完整,使用它的成员应该是错误的
  • @PasserBy 如果我错了,请纠正我,但在 A&lt;AplusB&gt; 的隐式实例化时 AplusB 已完成......(AplusB 中的别名声明不会隐式实例化 A 或B)
  • @MassimilianoJanes 你可能是对的,我对此不太熟悉。
  • FWIW, VC++ 2017 15.6 Preview 编译第二个。 Micro$oft 一直在实现对两阶段查找的部分合规性,这可能与它有关。
  • 这是CWG 287

标签: c++ templates language-lawyer template-meta-programming


【解决方案1】:

正如另一个answer 中所讨论的那样,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)

序列 (2)、(2.1)、(2.2) 和 (2.3) 是导致实例化的顺序,有效 PoI 在该声明之前。首先声明 (2),在 (2.3) 处,我们引用 (*),它不在范围内。如果 (1) 先出现,那么在 (1.3) 我们访问 (#),这确实在范围内。 (在 (2) 的后续声明中,A 的特化已经完全实例化,因此没有进一步的细微之处。)

如果您在“递归”别名之前声明所有“基本情况”别名,这是您第一个 sn-p 中的区别,它可以工作fine either way

【讨论】:

  • 我是否理解正确,该标准并不清楚这些代码 sn-ps 的格式是否正确?并且编译器拒绝这样的代码可以吗?
  • @D.Dmitriy 标准本身并不是特别清楚。但是任何定性前端都会表现得像 GCC 或 Clang。
猜你喜欢
  • 1970-01-01
  • 2012-04-20
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多