2017-07-14 6 views
2

テンプレートクラスを定義する方法は、テンプレートクラスから継承しますか?C++テンプレートクラスを継承

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 
+2

ファイル名と行番号のないコンパイルエラーが表示されます。また、typedefの代わりに 'using'を使うことをお勧めします。構文はより明確で、時にはより良いエラーメッセージを出すこともできると思います。 – xaxxon

+1

また、アンダースコアで始まる名前、大文字、または2つのアンダースコアで始まる名前は使用できません。たとえば_Sequenceは使用できません。 https://stackoverflow.com/a/228797/493106 – xaxxon

+2

@ xaxxon 2つの連続したアンダースコアを持つ任意の識別子*どこでも*それは許可されていません –

答えて

2

ここでの問題は、基本クラスLooperQueueは、テンプレートパラメータTpSequence、その完全な形はできる」に依存依存基底クラス、ということですテンプレート引数を知らなくても決定できます。標準C++では、依存しない名前(size_typereferencevalue_typeなど)は依存する基本クラスでは検索されません。

コードを修正するには、名前をベースクラス名で修飾するだけで十分です。これらの名前はインスタンシエーション時にのみ検索することができ、その時点で探索されなければならない正確な基盤特化がわかります。例えば

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

'* .h'ファイルに' StdQueue'を定義し、 '* .cpp'ファイルに' StdQueue'を実装できますか? –

+1

@Fantasy_RQG [テンプレートはヘッダファイルにのみ実装できますか?](https://stackoverflow.com/q/495021/3309790)を参照してください。 – songyuanyao

3

あなたも同じエラー、一つだけ定義されたエイリアスと、それを使用しようと、サブクラスでベースを考えてみますので、テンプレートのクレイジーな性質の

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

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

、コンパイラはvalue_typeはこの点にあるかを知ることはできません。

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

またはあなたが

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

基底クラス型の別名を使用するように意図されているusing宣言でコンパイラを語った:あなたはそれが基本クラスからどちらかそれを修飾することによって来ることを、それを指示する必要がありますコンパイラは、Tが何であるかを知り、テンプレートをインスタンス化するまで、value_typeが含まれていることを実際には知りません。 なぜ基本テンプレートを見ることができないのですか? - そのようなことは理論的には可能ですが、どのような専門分野が利用可能かはわかりません。どこかにあなたが

template<> 
class Base<int> {}; 

を持っていた場合次にDerived<int>は、他の場所でその範囲内value_type探ししなければならない、それはそれはあなたの元のコードで何をするかです。それはvalue_typeを見つけようとし、失敗します。この動作は、いくつかの驚くべき結果につながることができます:関連トピックの詳細地上アップ説明see this blog post

1

については

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

をあなたのコンパイルエラーの、ほとんど、すべてではないが、お使いのベースクラスの種類によるものです派生クラスの名前検索中に検査されません。 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; 
} 
+0

'typedef typename Base :: size_type size_type;'はtypenameを使って達成することができます :: size_type; ' –

+0

はい、すべての' typedef'は 'using'(エイリアス宣言)、 'typedef'の代わりに別名宣言を使うことを好みます。しかし、私は 'typedef'を残して、この例をFantasy_RQGの元のコードに近づけることにしました。 –

+0

あなたのコードは素晴らしいですが、私は関数定義を宣言と定義に分割することはできません。これを行う方法はありますか? –

関連する問題