【问题标题】:Calling method of template base class模板基类的调用方法
【发布时间】:2016-07-05 20:14:28
【问题描述】:

以下代码在 Visual Studio 2015 中编译(即使使用 /Za 选项)。它不能在 gcc 和 clang 上编译。

struct A
{
};

template<typename T>
struct B
{
  void f()
  {
  }
};

template<typename T>
struct C : B<T>
{
  void f()
  {
  }

  void g()
  {
    B::f();
  }
};

int main()
{
  C<A> c;
  c.g();

  return 0;
}

Demo

gcc - 错误:“模板结构 B”未使用模板参数
clang - 错误:“B”不是类、命名空间或枚举

哪种编译器符合标准规范?规格有歧义吗?

编辑
我在C 中添加了f() 以获得更相关的示例。

【问题讨论】:

    标签: c++ gcc visual-c++ visual-studio-2015 clang


    【解决方案1】:

    通常在这种情况下调用基类函数你会这样写:

    this->f();
    

    如果f 和g 都是静态的,你当然不能这样做,所以你可以写

    B<T>::f();
    

    这是因为B 已经在C 的声明范围内,所以编译器已经知道它是一个模板。如果你单独使用B::f(),编译器会给你一个错误,因为它知道B是一个模板,所以它应该有模板参数。

    您可能想知道为什么允许在B&lt;T&gt; 的定义中省略模板参数,但在C 的定义中却不能。要理解这一点,您需要知道每个类都有一个 injected-class-name,其行为类似于在类定义的最开头声明的 typedef。所以就好像B的定义以

    开头
    typedef B<T> B;
    

    在B&lt;T&gt; 的定义中使用B 会找到injected-class-name,而不是模板。但是当你在C 内部时,这个B 是不可见的,因为它是在B&lt;T&gt; 内部声明的,它是一个依赖基类,并且在非限定名称查找期间不搜索依赖基类范围(并且B 是在:: 的左边,所以B 的查找是不合格的)。这也有效:

    C::B::f();
    

    在这种情况下,找到了injected-class-name C,它引用了依赖类型C&lt;T&gt;,因此B的查找将在依赖基中搜索类 B&lt;T&gt; 并找到所需的 injected-class-name。

    【讨论】:

      【解决方案2】:

      问题出在struct C,来自B 的函数f 在没有模板参数的情况下被调用。

      【讨论】:

        【解决方案3】:

        编译器不知道您在B::f(); 中所指的B,请尝试将其更改为B&lt;T&gt;::f();。

        【讨论】:

        • 对,我知道 B::f() 有效。开发跨平台代码时,有些代码用一个编译器编译而不用其他编译器编译,这很烦人。我想知道关于它的标准是什么,以及三个编译器是否可以对齐以给出相同的编译结果(成功与否)......
        猜你喜欢
        • 1970-01-01
        • 2016-08-17
        • 1970-01-01
        • 2012-02-04
        • 2014-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-19
        相关资源
        最近更新 更多