14

我最近被(简化)咬了

struct Base {
    typedef char T;
};

template<typename T>
struct Foo : Base {
    T x[50];  // This is Base::T, not the template parameter
};

换句话说,类成员名称隐藏了模板参数(即使来自基类,因此在本地上下文中并不完全明显)。

做一些实验我发现:

struct Base {
    typedef char T;
};

template<typename T, typename B>
struct Foo : B {
    T x[50];  // This T is the template parameter,
              // even passing Base as B
};

这个明显荒谬的规则背后的理由(如果有的话)是什么?

我能想到的唯一方法是给出丑陋的模板参数名称,这也意味着不使用保留名称就不可能安全地编写模板(因为模板中使用的类可能会与参数名称冲突......请注意,很多 C++代码对私有成员使用丑陋的名称)。

PS:我没有深入研究这个问题的标准,但 g++ 和 clang++ 都同意这种行为,所以我不认为这是一个错误。

PPS:在实际代码中,被隐藏的模板参数名为tid,并且是整数而不是类型。-Wall不足以通知隐藏,我在用 valgrind 调试几个小时后发现了它。

4

1 回答 1

7

此规则(在[temp.local]/9中指定)是 11 年前创建的开放核心语言问题的主题 -核心问题 #459。CWG 对此进行了彻底的讨论。关于意图,迈克米勒提到

当前规范的基本原理非常简单:

  • “除非在派生类中重新声明,否则基类的成员也被视为派生类的成员。” (10 [class.derived] 第 2 段)

  • 在类范围内,成员隐藏非成员。

而已。因为模板参数不是成员,所以它们被成员名称隐藏(无论是否继承)。我觉得这并不“奇怪”,甚至不特别令人惊讶。

理由:

我们对更改表示同情,但当前规则直接不属于查找规则,因此它们没有“错误”。让私人成员不可见也可以解决这个问题。我们愿意查看提出该建议的文件。[..]
如果没有更详细地探讨该问题的文件,CWG 决定目前不考虑对现有规则进行更改。

不幸的是,还没有这样的论文被写出来,所以这个规则一直持续到今天。

于 2015-03-31T07:40:48.997 回答