【问题标题】:Multiple Inheritance from two derived classes with templates and constructors从具有模板和构造函数的两个派生类的多重继承
【发布时间】:2016-11-29 01:38:35
【问题描述】:

我正在遵循here 中的示例,但是我正在使用模板并调用其中一个派生类的构造函数。以下代码可以在没有模板的情况下使用,但包含时我不确定为什么会出现以下错误:

: error: no matching function for call to ‘AbsInit<double>::AbsInit()’
     NotAbsTotal(int x) : AbsInit(x) {};
                                   ^

代码如下:

#include <iostream>

using namespace std;

template<typename T>
class AbsBase
{
    virtual void init() = 0;
    virtual void work() = 0;
};

template<typename T>
class AbsInit : public virtual AbsBase<T>
{
public:
    int n;
    AbsInit(int x)
    {
        n = x;
    }
    void init() {  }
};

template<typename T>
class AbsWork : public virtual AbsBase<T>
{
    void work() {  }
};

template<typename T>
class NotAbsTotal : public AbsInit<T>, public AbsWork<T>
{
public:
    T y;
    NotAbsTotal(int x) : AbsInit(x) {};
};    // Nothing, both should be defined


int main() {
  NotAbsTotal<double> foo(10);
  cout << foo.n << endl;

}

【问题讨论】:

  • @TavianBarnes 哈哈谢谢!请回答
  • 这应该可以。但也许我的欺骗是错误的,因为它应该在 GCC 4.5 中得到修复,它大大早于 C++14。你的编译器和版本是什么?
  • 和编译命令。
  • AbsInit&lt;T&gt; 是一个依赖基类。 AbsInitAbsInit&lt;T&gt;本身范围内的注入类名,但由于AbsInit&lt;T&gt;的范围没有被检查,所以在名称查找的第一阶段可以找到的唯一AbsInit是一个类模板名(在搜索全局范围时),而不是引用 AbsInit&lt;T&gt; 的某些特定实例化的类型
  • @PiotrSkotnicki: C++11: 14.6.1/3 在一个例子中似乎是相反的。很遗憾您在重新打开之前没有真正阅读潜在的欺骗!

标签: c++ c++14


【解决方案1】:

您需要将 template-argument(在本例中为 T)传递给基础 template-class

改变这个

template<typename T>
class NotAbsTotal : public AbsInit<T>, public AbsWork<T>
{
public:
    T y;
    NotAbsTotal(int x) : AbsInit<T>(x) // You need to pass the template parameter
    {};
};    

【讨论】:

  • 这令人惊讶。 AbsInit 应该是一个可访问的名称,指的是AbsInit&lt;T&gt;。没有?
  • 啊,原来我曾经经历过这个:stackoverflow.com/q/8887864/560648
  • 虽然它应该在 GCC 4.5 中得到修复,它大大早于 C++14 ... hmmm ...
  • @LightnessRacesinOrbit,现在阅读您的答案。但是如果默认注入模板基类名称,编译器将如何解决这样的问题。 template &lt;typename T&gt; class A : B&lt;int&gt;, B&lt;float&gt; .... { A() : B() /*which of the B&lt;&gt;? */ {} };??
  • 那将是模棱两可的 obvs,您必须使用完整的类型名。
【解决方案2】:

在下面的sn-p...

template<typename T>
class NotAbsTotal : public AbsInit<T>
{
    NotAbsTotal(int x) : AbsInit(x) {}
};

...AbsInit&lt;T&gt;dependent base class

一个依赖基类是一个基类,它是一个依赖类型并且不是当前的实例化。

...并且试图使用不合格的injected-class-name (AbsInit) 来引用它,但是:

类的注入类名称(子句 [class])也被认为是该类的成员,用于名称隐藏和查找。

...然而,[temp.dep]/p3:

在类或类模板的定义中,依赖基类的范围 ([temp.dep.type]) 在非限定名称查找期间也不会检查类模板或成员的定义或类模板或成员的实例化期间。 [例子

typedef double A;
template<class T> class B {
  typedef int A;
};
template<class T> struct X : B<T> {
  A a;              // a has type double
};

[...]

结束示例 ]

因此,AbsInit 不能绑定到存在于 AbsInit&lt;T&gt; 自身范围内的 injected-class-name。该名称单独使用,受unqualified name lookup 约束,并引用全局命名空间中的类模板。

为避免错误或强制执行所需的名称解析,请将模板参数列表附加到类模板名称AbsInit

NotAbsTotal(int x) : AbsInit<T>(x) {}
//                          ~~^

或使用限定名称:

NotAbsTotal(int x) : NotAbsTotal::AbsInit(x) {}
//                   ~~~~~~~~~~^

备注:一旦基类不依赖(即使用具体类型,例如AbsInit&lt;int&gt;),您可以使用注入类名称的非限定形式。

【讨论】:

    猜你喜欢
    • 2019-01-09
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 2012-12-19
    • 1970-01-01
    • 2019-12-14
    • 2016-03-04
    • 2021-04-20
    相关资源
    最近更新 更多