4

how to define a template class inherit from template class ?

I want to wrap std::queue and std::priority_queue to a base class. In my case is LooperQueue. I use StdQueue in this way 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; private: std::queue<Tp, Sequence> mQueue; }; #endif //PBOTEST_STDQUEUE_H 
4
  • 2
    posting compiler errors without filenames and line numbers stinks. Also, I recommend using 'using' instead of typedef. The syntax is more clear and I think it can give better error messages sometimes, too. Commented Jul 14, 2017 at 4:14
  • 1
    Also, you are not allowed to use names that start with an underscore followed by a capital letter, or any name starting with two underscores. _Sequence, for example, is not allowed. stackoverflow.com/a/228797/493106 Commented Jul 14, 2017 at 4:21
  • 2
    @xaxxon any identifier with two consecutive underscores anywhere in it is not allowed Commented Jul 14, 2017 at 5:30
  • @xaxxon sorry about my error log post . I removed underscores, but error remain same. I don't understand about "using instead of typedef". is there more detail Commented Jul 14, 2017 at 5:31

3 Answers 3

8

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. You have to tell it that it comes from the Base class either by qualifying it:

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

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. Why can't it just look at the Base template? -- 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. It tries to find a value_type and fails. 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

Sign up to request clarification or add additional context in comments.

Comments

3

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. Standard C++ says that nondependent names (like size_type, reference and value_type) won't be looked up in dependent base classes.

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. 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 Comments

can I define StdQueue in *.h file and implement StdQueue in *.cpp file ?
1

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). 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:

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

5 Comments

typedef typename Base<T,S>::size_type size_type; can be accomplished with using typename Base<T,S>::size_type;
Yes, all of the typedefs can be accomplished with using (alias declarations), and I prefer to use alias declarations instead of typedef. However, I decided to leave the typedefs to make the example closer to Fantasy_RQG's original code.
your code works great , but I can't split function define into declaration and definition. Is there any way to do this ?
To split the function declaration from the definition, first leave the definition inside the class. It will look like this: size_type size() override; Then, after the class or in the .C file: template <typename T, typename S> typename MyClass<T,S>::size_type MyClass<T,S>::size() { return 0; } You can write the definition on different lines, of course. If you want me to edit the code in the answer to reflect this let me know.
BTW if you place the template definition in a .C or .cpp file, you'll need to explicitly instantiate the template class for particular types, which is restricting (and a different subject). I usually just place the definitions in .h files.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.