【问题标题】:g++ deriving from class with template parameterg ++从具有模板参数的类派生
【发布时间】:2012-05-29 11:31:48
【问题描述】:

考虑以下代码:

template<class T>
class Base {
  public:
    void doSomething(){}
};

template<class T>
class Derived : public Base<T> {
  public:
    void doMore() {
      doSomething(); //Affected line
    }
};

在用“受影响的行”注释的行中 g++ (4.7) 说:

test.cc:11:16: error: there are no arguments to ‘doSomething’ that depend on a template parameter, so a declaration of ‘doSomething’ must be available [-fpermissive]

现在我想知道:

  • 如果模板参数 T 不存在,则不会发生此错误。有什么区别?
  • g++ 显然能够解决这个问题(如果我添加 -fpermissive 它编译得很好)。我假设 g++ 试图为我作为“用户”(程序员)提供最佳体验。当 g++ 不接受此代码时,对我有什么好处?

谢谢! 内森

【问题讨论】:

  • 更改为this-&gt;doSomething()(或Base&lt;T&gt;::doSomething()),因为doSomething() 取决于T 的类型。
  • @hmjd:这很有趣..你能简要描述一下添加this-&gt;有什么帮助吗?
  • 查看this question 并在其中回答。
  • @Asha, this-&gt; 告诉编译器名称是一个成员,因此名称查找会延迟到第 2 阶段(实例化),此时基类的类型已知并且其成员的声明是可见

标签: c++ templates g++ compiler-options


【解决方案1】:

如果您不添加thisBase&lt;T&gt;,您编写的代码不符合标准 - GCC 想要阻止您这样做。另请参阅 GCC 4.7 的变更日志条目:

G++ 现在正确实现了两阶段查找规则,这样在模板中使用的非限定名称必须在模板定义点的范围内或通过实例化点的参数相关查找找到适当的声明.因此,依赖于在实例化点进行第二次非限定查找以查找在模板之后或在依赖库中声明的函数的代码将被拒绝。编译器将建议修复受影响代码的方法,并且使用 -fpermissive 编译器标志将允许代码在编译时出现警告。

template <class T>
void f() { g(T()); } // error, g(int) not found by argument-dependent lookup
void g(int) { } // fix by moving this declaration before the declaration of f

template <class T>
struct A: T {
  // error, B::g(B) not found by argument-dependent lookup
  void f() { g(T()); } // fix by using this->g or A::g
};

struct B { void g(B); };

int main()
{
  f<int>();
  A<B>().f();
}

(在这里找到:http://gcc.gnu.org/gcc-4.7/changes.html)。

【讨论】:

  • GCC 自至少 4.1 起拒绝了 OP 的示例,4.7 中的更改与依赖库中的名称查找无关。
【解决方案2】:

GCC Verbose Diagnostics wiki 页面对此进行了介绍。

g++不接受这段代码对我有什么好处?

它符合标准并与其他编译器一致,确保您的代码可移植且正确。

【讨论】:

  • 好的,符合标准。但我必须说,标准强迫我写“this->doSomething()”或使用“-fpermissive”让我很恼火,我不明白为什么标准不能“更好”。
  • 如果你专门化Base&lt;int&gt; 使得Base&lt;int&gt;::doSomething 是一个数据成员,而不是一个成员函数,那么实例化Derived&lt;int&gt;::doMore 是无效的,因为它会尝试“调用”一个数据成员.所以基类中名称的类型,或者它们是否存在,直到实例化时才能知道,所以在实例化之前查看基类是没有意义的。要告诉编译器名称可能来自基类并等到实例化进行查找,您必须限定名称或使用this-&gt;,否则查找将无法找到它。
  • ... 一种替代方法是编译器有时在定义时找到它,然后有时在实例化时“未找到”它,这将是不一致的,甚至更令人困惑。如果您想要不一致的“有时以这种方式工作,有时以这种方式工作”,那么请尝试 PHP ;-) 标准 尝试 给出一套关于如何编译模板的单一、明确的规则,其中一个结果是在模板中不合格的名称查找永远不会在依赖的基类中查找。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-30
  • 1970-01-01
  • 1970-01-01
  • 2021-04-13
  • 1970-01-01
  • 1970-01-01
  • 2012-09-25
相关资源
最近更新 更多