简体   繁体   English

C ++模板类继承

[英]C++ template class inherit

how to define a template class inherit from template class ? 如何定义模板类继承自模板类?

I want to wrap std::queue and std::priority_queue to a base class. 我想将std::queuestd::priority_queue包装到基类中。 In my case is LooperQueue . 在我的例子中是LooperQueue I use StdQueue in this way auto queue = new StdQueue<LooperMessage *>() . 我以这种方式使用StdQueue auto queue = new StdQueue<LooperMessage *>()

my class define compiler complain 我的类定义编译器抱怨

error log: 错误日志:

  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;

code: 码:

#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

I'm going to use a simpler example that gives you the same error, consider a base with just one alias defined and a subclass that tries to use it: 我将使用一个更简单的示例来提供相同的错误,考虑只定义一个别名的基础和尝试使用它的子类:

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

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

Because of the crazy nature of templates, the compiler can't know what value_type is at this point. 由于模板的疯狂性,编译器无法知道此时的value_type You have to tell it that it comes from the Base class either by qualifying it: 你必须通过限定它来告诉它它来自Base类:

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

or telling the compiler with a using declaration that you are intending to use a base class type alias 或者using声明告诉编译器您打算使用基类类型别名

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

The compiler can't actually know that Base<T> contains a value_type until it knows what T is and instantiates the template. 编译器实际上无法知道Base<T>包含value_type直到它知道T是什么并实例化模板。 Why can't it just look at the Base template? 为什么不能只看Base模板? -- such a thing would be theoretically possible, but it doesn't know what specializations will be available. - 这样的事情在理论上是可行的,但它不知道将有哪些专业化。 If somewhere else you had 如果你在其他地方

template<>
class Base<int> {};

Then Derived<int> would have to look for value_type elsewhere in its scope, and that's what it does in your original code. 然后Derived<int>必须在其范围内的其他地方查找value_type ,这就是它在原始代码中的作用。 It tries to find a value_type and fails. 它试图找到一个value_type并失败。 This behavior can lead to some surprising results: 这种行为可能会导致一些令人惊讶的结果:

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

For a more ground-up explanation on related topics you can read my medium post 有关相关主题的更全面的解释, 您可以阅读我的中文帖子

The issue here is that the base class LooperQueue is a dependent base class, which depends on the template parameter Tp and Sequence , then its complete type can't be determined without knowing the template arguments. 这里的问题是基类LooperQueue是依赖基类,它依赖于模板参数TpSequence ,然后在不知道模板参数的情况下无法确定其完整类型。 Standard C++ says that nondependent names (like size_type , reference and value_type ) won't be looked up in dependent base classes. 标准C ++表示不会在依赖基类中查找非依赖名称(如size_typereferencevalue_type )。

To correct the code, it suffices to make the names qualified by the base class name; 要更正代码,只需使名称由基类名称限定即可; then these names can be looked up only at the time of instantiation, and at that time the exact base specialization that must be explored will be known. 然后只能在实例化时查找这些名称,并且在那时必须知道必须探索的确切基本特化。 eg 例如

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;
};

Most, if not all, of your compilation errors are due to the types in your base class not being examined during name lookup of your derived class. 大多数(如果不是全部)编译错误是由于在派生类的名称查找期间未检查基类中的类型。 The C++ standard says that you should fully qualify the type names (see this question ). C ++标准说你应该完全限定类型名称(参见这个问题 )。 In other words, the types in your template base class are not visible from your derived class without their being fully qualified. 换句话说,如果没有完全限定,则派生类中不会显示模板基类中的类型。 Below is a simple example that compiles and runs with g++-6.3.0 -std=c++14 : 下面是一个用g++-6.3.0 -std=c++14编译和运行的简单示例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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM