C ++模板类继承

时间:2017-07-14 04:00:05

标签: c++ class templates inheritance name-lookup

如何定义从模板类继承的模板类?

我想将std::queuestd::priority_queue包装到基类中。在我的情况下是LooperQueue。 我以这种方式使用StdQueue auto queue = new StdQueue<LooperMessage *>()

我的类定义编译器抱怨

错误日志:

  In file included from /Users/rqg/ASProjects/PboTest/muses/src/main/cpp/Painter.cpp:10:
  /Users/rqg/ASProjects/PboTest/muses/src/main/cpp/util/StdQueue.h:14:5: error: unknown type name 'size_type'; did you mean 'size_t'?
      size_type size() override;
      ^~~~~~~~~
      size_t
  /Users/rqg/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/5.0.300080/include/stddef.h:62:23: note: 'size_t' declared here
  typedef __SIZE_TYPE__ size_t;
                        ^
  In file included from /Users/rqg/ASProjects/PboTest/muses/src/main/cpp/Painter.cpp:10:
  /Users/rqg/ASProjects/PboTest/muses/src/main/cpp/util/StdQueue.h:16:5: error: unknown type name 'reference'
      reference front() override;
      ^
  /Users/rqg/ASProjects/PboTest/muses/src/main/cpp/util/StdQueue.h:20:21: error: unknown type name 'value_type'; did you mean 'ARect::value_type'?
      void push(const value_type &x) override;
                      ^~~~~~~~~~
                      ARect::value_type
  /Users/rqg/Library/Android/sdk/ndk-bundle/sysroot/usr/include/android/rect.h:44:21: note: 'ARect::value_type' declared here
      typedef int32_t value_type;

#ifndef PBOTEST_LOOPERQUEUE_H
#define PBOTEST_LOOPERQUEUE_H

#include <queue>
#include <cstdlib>

template<typename Tp, typename Sequence = std::deque<Tp> >
class LooperQueue {
public:

    typedef typename Sequence::value_type                value_type;
    typedef typename Sequence::reference                 reference;
    typedef typename Sequence::const_reference           const_reference;
    typedef typename Sequence::size_type                 size_type;
    typedef          Sequence                            container_type;


    virtual size_type size()  = 0;

    virtual reference front() = 0;

    virtual void pop()= 0;

    virtual void push(const value_type &x) = 0;
};


#endif //PBOTEST_LOOPERQUEUE_H
 #ifndef PBOTEST_STDQUEUE_H
#define PBOTEST_STDQUEUE_H


#include "LooperQueue.h"

template<typename Tp, typename Sequence = std::deque<Tp> >
class StdQueue : public LooperQueue<Tp, Sequence> {
public:
    size_type size() override;

    reference front() override;

    void pop() override;

    void push(const value_type &x) override;

public:


private:
    std::queue<Tp, Sequence> mQueue;
};


#endif //PBOTEST_STDQUEUE_H

3 个答案:

答案 0 :(得分:4)

我将使用一个更简单的示例来提供相同的错误,考虑只定义一个别名的基础和尝试使用它的子类:

template <typename T>
class Base {
 public:
  using value_type = T;
};

template <typename T>
class Derived : public Base<T> {
  value_type func();  // error
};

由于模板的疯狂性,编译器无法知道此时value_type是什么。你必须通过限定它来告诉它它来自Base类:

template <typename T>
class Derived : public Base<T> {
  typename Base<T>::value_type func();
};

或告诉编译器using声明您打算使用基类类型别名

template <typename T>
class Derived : public Base<T> {
  using typename Base<T>::value_type;
  value_type func();
};

编译器实际上无法知道Base<T>包含value_type,直到它知道T是什么并实例化模板。 为什么不能只看Base模板? - 这样的事情在理论上是可行的,但它不知道可用的专业化。如果你在其他地方

template<>
class Base<int> {};

然后Derived<int>必须在其范围内的其他位置查找value_type,这就是它在原始代码中的作用。它试图找到value_type并失败。这种行为可能会导致一些令人惊讶的结果:

using value_type = char;
template <typename T>
class Derived : public Base<T> {
  value_type func(); // this is the global value_type = char, always
};

有关相关主题you can read my medium post

的更全面的解释

答案 1 :(得分:2)

这里的问题是基类LooperQueue是依赖基类,它取决于模板参数TpSequence,那么它的完整类型不能在不知道模板参数的情况下确定标准C ++表示非依赖名称(如size_typereferencevalue_type)不会在依赖基类中查找。

要更正代码,只需使名称由基类名称限定即可;然后只能在实例化时查找这些名称,并且在那时必须知道必须探索的确切基本特化。 e.g。

template<typename _Tp, typename _Sequence = std::deque<_Tp> >
class StdQueue : public LooperQueue<_Tp, _Sequence> {
public:
    typename LooperQueue<_Tp, _Sequence>::::size_type size() override;
    typename LooperQueue<_Tp, _Sequence>::reference front() override;
    void pop() override;
    void push(const typename LooperQueue<_Tp, _Sequence>::value_type &__x) override;
private:
    std::queue<_Tp, _Sequence> mQueue;
};

答案 2 :(得分:1)

大多数(如果不是全部)编译错误是由于在派生类的名称查找期间未检查基类中的类型。 C ++标准规定您应该完全限定类型名称(请参阅this question)。换句话说,如果没有完全限定,则派生类中不会显示模板基类中的类型。下面是一个使用g++-6.3.0 -std=c++14编译和运行的简单示例:

#include <iostream>
#include <deque>

using namespace std;

template <typename T, typename S = deque<T> >
class Base
{
public:
    typedef typename S::size_type size_type;

    virtual size_type size() = 0;
};


template <typename T, typename S = deque<T> >
class MyClass : public Base<T, S>
{
public:
    // type name has to be fully qualified
    typedef typename Base<T,S>::size_type size_type;

    // you could use "typename Base<T,S>::size_type" here instead
    size_type size() override { return 0; }
};


int main()
{
    MyClass<int> c;
    cout << c.size() << endl;
}