Using PImpl Idiom and Curiously Recurring Template Pattern - c++

I'm getting some compiling errors when creating constructors for my derived image classes while using PImpl Idiom and Curiously Recurring Template Pattern. The base class for image class implementations uses CRTP (Curiously Recurring Template Pattern) to enforce static dispatch instead of layering on another virtual call. Please tell me what I'm doing wrong. Please see the comments for where the errors occur
// Error: no matching constructor for initialization of 'jpeg_image::impl' [clang-diagnostic-error]
// Error: field has incomplete type 'jpeg_image::impl' [clang-diagnostic-error]
image.hpp
#include <memory>
#include <vector>
namespace image_wrapper {
class image {
public:
//ToDo: declare pure virtual functions
};
class jpeg_image final : public image {
class impl;
std::unique_ptr<impl> _impl;
public:
// Destructor and constructor for reading from a buffer of encoded_bytes
~jpeg_image();
jpeg_image(std::vector<uint8_t> encoded_bytes);
};
} //namespace image_wrapper
image.cpp
#include "image.hpp"
#include <boost/gil.hpp>
#include <functional>
namespace image_wrapper {
namespace {
template <class Derived>
class impl_base {
public:
// ToDo: implement base class functions
protected:
// Constructor
explicit impl_base(std::vector<uint8_t> encoded_bytes) :
_unencoded_image{ std::bind(&impl_base<Derived>::initialize_unencoded_image, this) }, _encoded_bytes{ encoded_bytes }
{
}
private:
boost::gil::rgb8_image_t initialize_unencoded_image() { return static_cast<Derived&>(*this).decode_bytes(); }
boost::gil::rgb8_image_t _unencoded_image;
std::vector<uint8_t> _encoded_bytes;
};
} // namespace
/*
* JPEG Class Definitions
*/
class jpeg_image::impl : public impl_base<jpeg_image::impl> {
public:
// Error: field has incomplete type 'jpeg_image::impl'
jpeg_image::impl(std::vector<uint8_t> encoded_bytes) : impl_base<jpeg_image::impl>(encoded_bytes) {}
boost::gil::rgb8_image_t decode_bytes()
{
// ToDo: implement decode_bytes()
}
};
// Error: no matching constructor for initialization of 'jpeg_image::impl' [clang-diagnostic-error]
jpeg_image::jpeg_image(std::vector<uint8_t> encoded_bytes) : _impl(new jpeg_image::impl(encoded_bytes)) {}
// Jpeg Image Destructor
jpeg_image::~jpeg_image() = default;
} // namespace image_wrapper

Related

How can I offload dependency injected template class providing templated functions to pimpl class

I have an application class that can take in a dependent class as a template argument to the constructor. This dependent class is required to provide certain templated functions that the application class can call. I would like to offload this dependent class object to a pimpl class so the application class is not a template class and thus header-only.
Here is a rough idea of what I mean.
///////////
// impl.h
///////////
template<typename Helper>
struct Impl
{
public:
Impl(Helper& helper) : helper_(helper)
{
}
template <typename T>
void someHelperFn1(T t)
{
helper_->fn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return helper_->fn2();
}
private:
Helper& helper_;
};
///////////
// app.h
///////////
#include "impl.h"
class App
{
public:
template<typename Helper>
App(Helper &h) :impl_(new Impl) {}
template <typename T>
void someHelperFn1(T t)
{
impl_->someHelperFn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return impl_->someHelperFn2();
}
void someAppFn();
private;
std::unique_ptr<Impl> impl_;
};
///////////
// app.cpp
///////////
void App::someAppFn()
{
// some useful code
}
I realize the above code doesn't compile since Impl is really a template class and so App would also be a template class too. That is what I would like to avoid so that App is not a header-only class. I found something similar except the functions that I want to call from the helper dependency are template functions and they are not in this case. It seemed pretty close otherwise to what I wanted to do.
Any ideas on how I can avoid making App a template class?
I tried making the helper class use a common base class but that is not really possible with the template functions.
Also, note that I am limited to C++ 17 for the compiler.
You will need to make sure the public header file (the one with the class that has the pimpl pointer) doesn't expose the header file only class template of the implementation. Use an interface for that like this.
I did not dependency inject the implementation because that should not be needed.
#include <memory>
#include <iostream>
// public header file
// for pimpl pattern I often use an interface
// (also useful for unit testing later)
class PublicItf
{
public:
virtual void do_something() = 0;
virtual ~PublicItf() = default;
protected:
PublicItf() = default;
};
// the public class implements this interface
// and the pimpl pointer points to the same interface
// added advantage you will have compile time checking that
// the impl class will all the methods too.
class PublicClass final :
public PublicItf
{
public:
PublicClass();
virtual ~PublicClass() = default;
void do_something() override;
private:
std::unique_ptr<PublicItf> m_pimpl; // the interface decouples from the template implementation (header file only)
};
// private header file
// this can now be a template
template<typename type_t>
class ImplClass final :
public PublicItf
{
public:
void do_something() override
{
m_value++;
std::cout << m_value << "\n";
}
private:
type_t m_value{};
};
// C++ file for Public class
// inlcude public header and impl header (template)
PublicClass::PublicClass() :
m_pimpl{ std::make_unique<ImplClass<int>>() }
{
};
void PublicClass::do_something()
{
m_pimpl->do_something();
}
// main C++ file
int main()
{
PublicClass obj;
obj.do_something();
return 0;
}

can't find overloaded method from inherited class template

This is the first time I am using class templates so please don't be to harsh if I made a simply mistake.
I have a class template class A<class T>. It has a method init() that is pure virtual and therefore will be implemented separately in every derived class. What all these possible derived classes will have in common is an init(T* i_x) which basically does some general stuff and then calls the init(). Because this will be the same for every derived class I want to define it in the base class template already. But somehow my compiler doesn't find the right function.
If I try to use the init(T* i_x) on an object of a derived class A_der I get the error:
no matching function for call to 'A_der::init(B_der*)
The classes used for the template parameter T will all be derived from another class B. Therefore the error message involves the class B_der which is derived from class B.
I boiled the problem down to a small example, which should involve everything that is important for the problem. If I try to compile this example in Visual Studio (normally I work in STM32CubeIDE) I get the following error
Severity Code Description Project File Line Suppression State
Error C2660 'A_der::init': function does not take 1
arguments template_class-overload_inherited_method [...]\main.cpp 8
So somehow the only function the compiler finds at this point is init() but not the base class template method init(T* ).
Can somebody please tell me why it is like that and what can I do to get the behaviour I want (without implementing a similar init(T* ) in every derived class of A?
Here is my example code:
base class template A - declaration - A.hpp
template<class T>
class A
{
protected:
T* m_x;
public:
virtual void connect(T* i_x) final;
virtual void init() = 0;
virtual void init(T* i_x) final;
};
base class template A - implementation - A.cpp
#include "A.hpp"
template<class T>
void A<T>::connect(T* i_x)
{
//some checks
m_x = i_x; //connects object of B to A
}
template<class T>
void A<T>::init(T* i_x)
{
connect(i_x);
init();
}
derived class A_der
#include "A.hpp"
#include "B_der.hpp"
#pragma once
class A_der : public A<B_der>
{
void init() override;
};
void A_der::init()
{
//Initialization which needs a B_der connected already
}
main.cpp
#include "B_der.hpp"
#include "A_der.hpp"
int main(void)
{
B_der testB;
A_der testA;
testA.init(&testB);
return 0;
}
For the sake of completeness:
class B
{
};
class B_der : public B
{
};
EDIT - Solved
Thanks a lot for the fast replies.
The combination of the comments from #BoP and #Jarod42 solved the problem.
I had to unhide the method with using A<B_der>::init (actually renaming might be the more elegant way) and move the implementation of A into A.hpp.
I will offer the updated example which builds successfully with Visual Studio 2019 for me here:
base class A
template<class T>
class A
{
protected:
T* m_x;
public:
virtual void connect(T* i_x) final;
virtual void init() = 0;
virtual void init(T* i_x) final;
};
template<class T>
void A<T>::connect(T* i_x)
{
//some checks
m_x = i_x; //connects object of B to A
}
template<class T>
void A<T>::init(T* i_x)
{
connect(i_x);
init();
}
derivad class A_der
A_der.hpp
#include "A.hpp"
#include "B_der.hpp"
class A_der : public A<B_der>
{
public:
void init() override;
using A<B_der>::init;
};
A_der.cpp
#include "A_der.hpp"
void A_der::init()
{
//Initialization which needs a B_der connected already
}
main.cpp
#include "B_der.hpp"
#include "A_der.hpp"
int main(void)
{
B_der testB;
A_der testA;
testA.init(&testB);
return 0;
}
for completeness
B.hpp
class B
{
};
B_der.hpp
#include "B.hpp"
class B_der : public B
{
};
I also forgot to make the methods of A_der public in the earlier example, this is corrected here. And I removed the #pragma onces in this example.
class A_der : public A<B_der>
{
void init() override;
};
When you declare a function init in the derived class, it hides all things named init from the base class. This is just like when declaring something in an inner scope - it hides things with the same name from outer scopes.
There are ways to import the hidden names, but an easy solution would be to just chose a different name, like init_base. Or, probably better, pass a parameter to the class constructor.

Error: expected ‘)’ before ‘*’ token despite not include-loop

I have a class RenderMachine which includes RenderObject and vice versa. I know there have been tons of questions about this error, but the solution for this doesn't do anything.
They say the error is mostly because a include-loop but I don't have one because in the RenderObject header I only allocate memory for a pointer to RenderMachine and vice versa.
RenderObject.h
#pragma once
#include "RenderMachine.h"
class RenderObject
{
public:
RenderObject(RenderMachine* rm){}
};
RenderMachine.h
#pragma once
#include "RenderObject.h"
class RenderMachine
{
public:
void add(RenderObject* renderObject);
};
The exact error is
error: expected ‘)’ before ‘*’ token
RenderObject(RenderMachine* rm)
^
Edit:
#include "RenderMachine.h"
class RenderMachine;
class RenderObject : public sf::Drawable
{
private:
int renderId;
public:
RenderObject(RenderMachine* rm){ (*rm).add(*this); }
int getRenderId() const { return renderId; }
#include "RenderObject.h"
class RenderMachine
{
std::vector< std::vector<sf::Drawable*> > renderVector;
public:
void add(RenderObject* renderObject);
And RenderMachine.cpp
#include "RenderMachine.h"
void RenderMachine::add(RenderObject* renderObject)
{
renderVector[(*renderObject).getRenderId()].push_back(renderObject);
}
Your call to add in the constructor of RenderObject should be done when RenderMachine is known (when it's a complete type). This goes for all calls to an object of the other type that you now have in your header files. Like this:
// RenderObject.h
class RenderMachine;
class RenderObject {
public:
RenderObject(RenderMachine* rm);
};
// RenderMachine.h
class RenderObject;
class RenderMachine {
public:
void add(RenderObject* renderObject);
};
// RenderObject.cpp
RenderObject::RenderObject(RenderMachine* rm) {
rm->add(this);
}
// RenderMachine.cpp
void RenderMachine::add(RenderObject* ro) {
}
You have a classic chicken-and-egg problem. The compiler cannot parse one header without first parsing the other header, because the classes in the headers refer to each other.
The solution is to use a forward declaration like this:
#include "RenderMachine.h"
class RenderMachine; // forward declaration
class RenderObject
{
public:
RenderObject(RenderMachine* rm){}
};

Error in initializing new object in other class using "this" pointer of the other

I have two classes: SessionCardsMode and SetOfCards. SessionCardsMode takes in its constructor pointer to object of SetOfCards. When I try to create dynamically new SessionCardsMode object in SetOfCards method initializing it with this pointer I get information: "Cannot initialize type 'SessionCardsMode' with rvalue of type 'SetOfCards*'". It looks like I haven't proper constructor, but I have provided it. I don't know why it doesn't work. The problem is in SetOfCards::getSessionCards method in the first line of it. I've found that if I try to create the same object in body of class SessionCardsMode using identical statement everything works fine, but if I try to make it out of class I get the error.
//////////////////////////////SesionCardsMode.h
#pragma once
#include "Card.h"
#include "SetOfCards.h"
class SessionCardsMode
{
protected:
SetOfCards* m_setData;
std::forward_list<Card*> m_sessionSet;
public:
explicit SessionCardsMode(SetOfCards* set) : m_setData(set) {};
virtual Card* getCard();
//allows making combination of set setup by mixing classes that derives
//from ModeOfSet
void addAndShuffle(const SessionCardsMode* mode);
};
///////////////////////////////SetOfCards.h
#pragma once
#include "Card.h"
#include "SessionCardsMode.h"
class SetOfCards
{
private:
std::vector<Card> m_cardSet;
std::string m_setName;
public:
SetOfCards()=default;
explicit SetOfCards(std::string setName);
template<typename Iter>
SetOfCards(Iter begin, Iter end, std::string setName);
SessionCardsMode* getSessionCards(std::vector<CreatorAndInitVal> creators);
};
////////////////////////////////////////SetOfCards.cpp
#include "SetOfCards.h"
SessionCardsMode* SetOfCards::getSessionCards(
std::vector<CreatorAndInitVal> m_sessionCardsCreators)
{
SessionCardsMode* sessionCards=new SessionCardsMode(this); // error here
return sessionCards;
}
I don't understand why you don't get an error when you declare the constructor of SessionCardsMode (when you are compiling SetOfCards.cpp) - as far as I can see, at that point, SetOfCards is not defined.
Anyway, the solution to your problem is not to #include any of the headers in other headers, but to declare (not define) the other classes. So:
//////////////////////////////SesionCardsMode.h
#pragma once
class Card;
class SetOfCards;
class SessionCardsMode
{
protected:
SetOfCards* m_setData;
std::forward_list<Card*> m_sessionSet;
public:
explicit SessionCardsMode(SetOfCards* set) : m_setData(set) {};
...
};
///////////////////////////////SetOfCards.h
#pragma once
class Card;
class SessionCardsMode;
#include <vector> // You need this
#include <string>
class SetOfCards
{
private:
std::vector<Card> m_cardSet;
std::string m_setName;
public:
SetOfCards()=default;
explicit SetOfCards(std::string setName);
...
};
////////////////////////////////////////SetOfCards.cpp
#include "SetOfCards.h" // This should always be first
#include "..." // You'll probably need some more here.
SessionCardsMode* SetOfCards::getSessionCards(
std::vector<CreatorAndInitVal> m_sessionCardsCreators)
{
SessionCardsMode* sessionCards=new SessionCardsMode(this); // Error should be fixed
return sessionCards;
}

c++ inheritance and templates not compiling

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() {...}