模板参数名称隐藏

Template parameter name hiding

我最近被(简体)咬了

struct Base {
    typedef char T;
};

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

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

做一些实验我发现:

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
};

这个看似荒谬的规则背后的基本原理(如果有的话)是什么?

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

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

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

此规则(在 [temp.local]/9) is subject of an open core language issue created over 11 years ago - core issue #459 中指定。CWG 对此进行了彻底讨论。关于意图,Mike Miller 提到

The rationale for the current specification is really very simple:

  • “Unless redeclared in the derived class, members of a base class are also considered to be members of the derived class.” (10 [class.derived] paragraph 2)

  • In class scope, members hide nonmembers.

That's it. Because template parameters are not members, they are hidden by member names (whether inherited or not). I don't find that “bizarre,” or even particularly surprising.

理由:

We have some sympathy for a change, but the current rules fall straightforwardly out of the lookup rules, so they're not “wrong.” Making private members invisible also would solve this problem. We'd be willing to look at a paper proposing that.[..]
The CWG decided not to consider a change to the existing rules at this time without a paper exploring the issue in more detail.

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