This question already has answers here:
Accessing inherited variable from templated parent class [duplicate]
(2 answers)
Closed 7 years ago.
I have something that i can't understand.
With one basic template class:
#ifndef DBUFFER_HPP
#define DBUFFER_HPP
#include <memory>
namespace memory {
template <template <typename T, class Alloc = std::allocator<T> > class Stock, class Unit>
class DBuffer {
typedef Stock<Unit> buffer_t;
protected:
const std::size_t m_sizeMax;
std::unique_ptr<buffer_t> m_data;
std::unique_ptr<buffer_t> m_backData;
public:
DBuffer(const std::size_t sizeMax) : m_sizeMax(sizeMax),
m_data(new buffer_t()),
m_backData(new buffer_t()) {}
virtual ~DBuffer() = default;
public:
const buffer_t& current() { return *m_data; }
void swap() { m_data.swap(m_backData); }
};
}
#endif
I just want to inherit from it, but :
#ifndef VIDEO_BUFFER_HPP
#define VIDEO_BUFFER_HPP
#include "dbuffer.hpp"
#include <deque>
namespace video {
template <typename T>
class VideoBuffer : public memory::DBuffer<std::deque, T> {
private:
static const unsigned int VIDEO_FPS_MAX = 60;
public:
VideoBuffer() : memory::DBuffer<std::deque, T>(VIDEO_FPS_MAX){}
~VideoBuffer() = default;
private:
void pop_to_back() {
m_backData->push_front(std::move(m_data->front()));
if (m_backData->size() > m_maxSize)
m_backData->pop_back();
m_data->pop_front();
}
#endif
But the only error is a not declared on every member that i tried to call from the base class.
Maybe i have a problem because some template type is not specified?
If somebody can explain why, i'll be thanks full.
To resume comment:
You have to replace private: by protected: to access parent members and inform that the members are dependant name: (for example by using this->)
void pop_to_back() {
this->m_backData->push_front(std::move(this->m_data->front()));
if (this->m_backData->size() > this->m_maxSize)
this->m_backData->pop_back();
this->m_data->pop_front();
}
Related
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 5 years ago.
Pure Virtual Class, AbstractThing.hpp:
#ifdef ABSTRACT_INTERFACE_FOR_THING
#define ABSTRACT_INTERFACE_FOR_THING
namespace A
{
namespace B
{
template <class T>
class AbstractThing
{
public:
virtual ~AbstractThing() = 0;
virtual T GetStatus() = 0;
};
}
}
#endif
Header File, Thing.hpp:
#ifdef _THING_H
#define _THING_H
#include "AbstractThing.hpp"
namespace A
{
namespace B
{
template <class T>
class Thing : public AbstractThing<T> {
public:
Thing();
~Thing();
T GetStatus();
};
}
}
#endif
Source file, Thing.cpp,
#include "Thing.hpp"
namespace A
{
namespace B
{
template <class T>
Thing<T>::Thing() {}
template <class T>
Thing<T>::~Thing() {}
template <class T>
T Thing<T>::GetStatus() { ... }
}
}
I keep running into this issue where compiler the complains about the class name (Thing) not being a type. However, it is declared in the header file. From reading other posts, it seems like this issue is generally caused by failing to pre-declare a function or class. However, I don't see why my code does not accomplish this. I thought that it might be a namespace issue because GetStatus() will compile if I remove the namespace access (Thing::), but removing the namespaces did not help.
#ifdef ABSTRACT_INTERFACE_FOR_THING
and
#ifdef _THING_H
should be:
#ifndef ABSTRACT_INTERFACE_FOR_THING
^
and
#ifndef _THING_H
^
And as suggested by #Amadeus, templates shouldn't be implemented in source files.
This question already has answers here:
templates: parent class member variables not visible in inherited class
(3 answers)
Closed 8 years ago.
When I compile the following templated C++ code with GCC 4.8.3
template <typename dtype> class Base {
public:
dtype base;
dtype ceiling;
Base() { };
virtual ~Base() { };
};
template<typename dtype> class Building : public Base<dtype> {
public:
dtype wall;
Building(dtype concrete) {
Base<dtype>::base=concrete;
ceiling=concrete;
wall=concrete;
};
~Building() { };
};
int main (int argc, char* argv[]) {
Building<float>* building=new Building<float>(2.0);
std::cout << building->base << std::endl;
}
I get the error
error: ‘ceiling’ was not declared in this scope
ceiling=concrete;
So it appears that
Base<dtype>::base=concrete;
works, but
ceiling=concrete;
does not. Is there any way I can mogrify this templated code so that, in the derived class constructor I can just reference "ceiling" from the templated base class without having to clarify which class it is from?
Thanks in advance
You can use this->ceiling.
I am currently having an issue with templated methods. I have this public class implementing a template method:
namespace Private { class InternalClass; }
namespace Public
{
class PublicClass
{
public:
PublicClass();
virtual ~PublicClass();
template<class T>
bool Add(bool primary);
private:
Private::InternalClass* _pInternal;
};
template<class T>
bool PublicClass::Add(bool primary) { return _pInternal->Add<T>(primary); }
}
The internal class is implemented that way:
namespace Private
{
class InternalClass
{
public:
InternalClass();
virtual ~InternalClass();
template <class T>
bool Add(bool primary);
};
template<class T>
bool InternalClass::Add(bool primary) { return false; }
}
As this internal class header won't be available with the provided sources, I must class forward it within the PublicClass header and I add the include to PrivateClass.h inside the PublicClass.cpp file.
1) Any idea why I would be getting the following error:
error : member access into incomplete type 'Private::InternalClass' / note: forward >declaration of 'Private::InternalClass'
2) What would be the best way of hiding my PublicClass::Add() implementation?
UPDATED
Reason for error at 1) is because of this as stated by Cornstalks.
For 2), how can I hide my implementation without including PrivateClass.h within the PublicClass header file?
You have encountered a very interesting problem - you want to implement the PImpl idiom where the privately implemented class has a template method. Well, this can be solved, meaning you CAN hide the template's implementation, but only when you know which types will be used to instantiate your Add<T> method in your program.
Say, your template will work only with types AClass and BClass. Then you can split your files as follows (comments are inlined):
File public.h:
#ifndef PUBLIC_H
#define PUBLIC_H
// Forward declaration ! It's sufficient in this case !
namespace Private { class InternalClass; }
// Declare all classes your Add<T> method should work with
struct AClass {};
struct BClass {};
namespace Public
{
class PublicClass
{
public:
PublicClass() {}
virtual ~PublicClass() {}
template <typename T>
bool Add(bool primary); // DO NOT implement this method, just declare
private:
Private::InternalClass* _pInternal;
};
// "Explicit instantiation declarations", for each type the method will work with:
extern template bool PublicClass::Add<AClass>(bool primary);
extern template bool PublicClass::Add<BClass>(bool primary);
}
#endif
File public.cpp:
#include "public.h"
// NOTE: this is hidden in CPP file, noone will see your implementation
namespace Private
{
class InternalClass
{
public:
InternalClass() {}
virtual ~InternalClass() {}
template <typename T>
bool Add(bool primary);
};
// Magic! Here is the actual implementation of your private method
template <typename T>
bool InternalClass::Add(bool primary)
{
return false;
}
}
namespace Public
{
// Original definition moved to CPP file !
template <typename T>
bool PublicClass::Add(bool primary)
{
return _pInternal->Add<T>(primary);
}
// And again list the allowed types, this time using "explicit instantiation definitions"
template bool PublicClass::Add<AClass>(bool primary);
template bool PublicClass::Add<BClass>(bool primary);
}
File main.cpp:
#include "public.h"
int main()
{
Public::PublicClass pc;
pc.Add<AClass>(true); // works !
pc.Add<BClass>(false); // works !
// pc.Add<int>(true); linker error as expected,
// becuase there is no explicit instantiation for Add<int>
return 0;
}
How do I use pimpl for a templated class, when I explicitly instantiate the templates?
All I need is an example code.
What I have tried is:
// MyTemplatedClass.h
template< class T >
class MyTemplatedClass
{
private:
class Impl;
Impl* _pimpl;
public:
void PublicMethod();
}
Here my implementation goes:
// MyTemplatedClass.cpp
template< class T >
class MyTemplatedClass<T>::Impl
{
public:
void PublicMethod();
}
template <class T>
void MyTemplatedClass<T>::Impl::PublicMethod()
{
...
}
Forwarding method call to implementation class:
template< class T >
void MyTemplatedClass<T>::PublicMethod()
{
_pimpl->PublicMethod();
}
Explicit instantiation:
Example with int and double:
template class MyTemplatedClass< int >;
template class MyTemplatedClass< double >;
But it doesn't seem to work.
This would answer your question, but I doubt it does what you hoped to achieve. I suspect you would want to declare the template implementation outside the scope of MyTemplatedClass. It might be a better design to inherit from the template implementation instead of having it as a member variable.
If you compiler does not support extern template declarations I cannot see that having a template pointer to implementation adds any value. You would after all have to have the implementation details you wanted to hide away in the header file anyway.
#include <iostream>
template < class T > class MyTemplatedClass {
private:
template < class U> class Impl {
public:
void ImplPublicMethod() {
std::cout << "Standard implementation" << std::endl;
}
};
Impl<T> * _pimpl;
public:
MyTemplatedClass() : _pimpl(new Impl<T>) { }
~MyTemplatedClass() { delete _pimpl; }
void publicMethod() {
_pimpl->ImplPublicMethod();
}
};
template<> class MyTemplatedClass<int> {
private:
class Impl {
public:
void ImplPublicMethod() {
std::cout << "Integer specialisation" << std::endl;
};
};
Impl * _pimpl;
public:
MyTemplatedClass() : _pimpl(new Impl) { }
~MyTemplatedClass() { delete _pimpl; }
void publicMethod() {
_pimpl->ImplPublicMethod();
}
};
int main(int argc, char ** argv) {
MyTemplatedClass<char> charVersion;
charVersion.publicMethod();
MyTemplatedClass<int> intVersion;
intVersion.publicMethod();
return 0;
}
Methods of a template class always have to be defined in the header. You cannot have a MyTemplatedClass.cpp as compilation unit on its own. What you can do is to #include the file containing the definitions of the methods at the end of MyTemplatedClass.h so that declaration and definition are at least separated at file level. So your problem may be fixed by adding
#include "MyTemplatedClass.cpp"
at the end of MyTemplatedClass.h.
I use pimpls with template classes in my own code, it works for me that way. Your code looks about right - I'd use a std::unique_ptr for pimpl, but I don't see any problems with how you're doing it.
I am trying to implement a generic hashlist class using templates and I am trying to inherit from the base class but getting lots of compile errors. Here is my code:
#ifndef BASEHASHLIST_H_
#define BASEHASHLIST_H_
#include <string>
#include <boost/unordered_set.hpp>
#include <iostream>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
template <typename T>
class BaseHashList
{
private:
boost::interprocess::interprocess_semaphore m_semaphore;
protected:
boost::unordered_set<T> m_hsHashSet;
typename boost::unordered_set<T>::iterator m_hsIter;
public:
BaseHashList();
};
template <typename T>
BaseHashList<T>::BaseHashList():m_semaphore(1){}
#endif /* BASEHASHLIST_H_ */
And here is the class that is inheriting from the base class:
#ifndef ACCOUNTLIST_H_
#define ACCOUNTLIST_H_
#include "BaseHashList.h"
class AccountList : public BaseHashList<unsigned long>
{
public:
AccountList(std::string p_strFile, unsigned long p_ulMaxAccountNo);
~AccountList(void);
int m_iVersion;
std::string m_strFilePath;
private:
unsigned long m_ulMaxAccountNo;
};
#endif /* ACCOUNTLIST_H_ */
and here is the cpp file:
#include "AccountList.h"
AccountList::AccountList(std::string p_strFile, unsigned long p_ulMaxAccountNo)
: BaseHashList<unsigned long>::m_hsHashSet<unsigned long>(),
m_iVersion(0),
m_strFilePath(p_strFile)
{
m_ulMaxAccountNo = p_ulMaxAccountNo;
}
AccountList::~AccountList(){}
I am receiving a lot of compile time errors such as:
expected template-name before token '<'
expected '(' before token '<'
For such a simple task I spent couple of hours and I am super frustrated, does anybody see what I am doing wrong here?
This initaliser in AccountList's constructor looks wrong to me:
BaseHashList<unsigned long>::m_hsHashSet<unsigned long>()
You should initalise the members of BaseHashList inside a constructor of BaseHashList itself, one will always either explicitly or implicitly be called.
This example is simplified and similarly wrong:
struct A {
int bar;
};
struct B : A {
B() : A::bar(0) {}
};
(saying bar(0) would also be wrong there)
However you can get the desired behaviour:
struct A {
A() : bar(0) {}
int bar;
};
struct B : A {
B() {} // Implicitly calls A::A although we could have explicitly called it
};
The constructor of A gets called and given a chance to initalise its members here still.
When you inherit from a template class, you have to add the template instruction to the child class too :
template <typename T>
class A : public B<T>
You also have to add the template instruction before the definition of constructors and methods :
template <typename T>
A<T>::A() : B<T>() {...}
template <typename T>
A<T>::~A() {...}