模板参数名称隐藏

时间:2015-03-31 07:05:00

标签: c++ templates language-lawyer name-lookup name-hiding

我最近被(简化)

咬了
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 ++代码都使用uglyfied名称作为私有成员。)

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

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

1 个答案:

答案 0 :(得分:7)

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

  

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

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

  •   
  • 在班级范围内,成员会隐藏非成员。

  •   
     

那就是它。因为模板参数不是成员,所以它们是   隐藏成员名称(无论是否继承)。我找不到   “离奇,”甚至特别令人惊讶。

理由:

  

我们对变更表示同情,但目前的规则直接落在查询规则之外,所以它们并非“错误”。让私人成员隐身也会解决这个问题。我们愿意看一篇提出这一建议的论文。[...]
CWG决定在没有更详细地探讨该问题的论文的情况下,此时不考虑更改现有规则

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