Reputation: 153
Here I was designing snall Pipe class hierarchy, problem is, I want to make the hierarchy minimal to the final user , so the only thing he has to do is to overwrite the virtual function like this :
template <typename T> class Processable{
protected:
public:
std::thread processLoop;
void myWrapper(Processable<T>* pp ){ pp->processLoopFunction();};
virtual void processLoopFunction() = 0 ;
Processable( ):processLoop(&Processable<T>::myWrapper,this,this){ processLoop.detach();};
~Processable( ){};
};
template <typename T> class Source ;
template <typename T> class Sink : public virtual Processable<T>{
// virtual void processChunk(void) = 0;
// virtual void isChunkReady(void) = 0;
protected:
public:
Source<T>* mySource;
Sink():mySource(nullptr){};
};
template <typename T> class Source : public virtual Processable<T>{
protected:
public:
lockfreequeue<T> myOutputDataBuffer;
void setSink(Sink<T>&);
virtual void processLoopFunction() = 0 ;
};
template <typename T> class Pipe : public virtual Source<T>, public virtual Sink<T>{
public:
virtual void processLoopFunction() = 0 ;
};
template <typename T> Pipe<T>& operator|(Source<T>& lhs, Pipe<T>& rhs ){ lhs.setSink(rhs) ;return rhs;};
template <typename T> Sink<T>& operator|(Source<T>& lhs, Sink<T>& rhs ){ lhs.setSink(rhs) ;return rhs;};
template <typename T> class PipeDouble: public Pipe<T>{
public:
virtual void processLoopFunction() ;
};
template <typename T> class OutputSink : public Sink<T>{
public:
virtual void processLoopFunction() ;
};
template <typename T> void Source<T>::setSink(Sink<T>& pp){
pp.mySource = this ;
};
template <typename T> class FileSource : public Source<T>{
std::ifstream myInputFile;
public:
FileSource(string filename):myInputFile(filename){};
virtual void processLoopFunction() ;
};
template <typename T> class NumberSource : public Source<T>{
public:
NumberSource(){};
virtual void processLoopFunction() ;
};
template <typename T> void OutputSink<T>::processLoopFunction(){
T tmp;
while(true){
if(this->mySource!=nullptr){
this->mySource->myOutputDataBuffer.pop(tmp);
cout << tmp << endl;
}
}
}
template <typename T> void FileSource<T>::processLoopFunction(){
T ll = 0;
while(myInputFile >> ll){
this->myOutputDataBuffer.push(ll);
}
}
template <typename T> void NumberSource<T>::processLoopFunction(){
T ll = 0 ;
while(true){
this->myOutputDataBuffer.push(ll);
ll++;
ll++;
}
}
template <typename T> void PipeDouble<T>::processLoopFunction(){
T tmp;
while(true){
if(this->mySource!=nullptr){
this->mySource->myOutputDataBuffer.pop(tmp);
tmp = tmp + tmp;
this->myOutputDataBuffer.push(tmp);
}
}
}
Of course I end up with
tom@oberon:~/CPP/Pipes> ./a.out pure virtual method called terminate called without an active exception Aborted
But not always ( for some derived classes it throws that error , for some others don't ) ; Is there some nice way of doing it , besides initializing std::thread processLoop; in every derived class separatly ?
Upvotes: 0
Views: 141
Reputation: 275650
Don't use inheritance.
template<typename T, typename Engine>
struct Processable {
Engine e;
std::thread myThread;
Processable( Processable&& ) = default;
Processable( Processable & ) = delete;
Processable( Processable const& ) = delete;
Processable( Processable const&& ) = delete;
Processable() = delete;
Processable& operator=(Processable const&) = delete;
Processable& operator=(Processable &&) = delete;
template<typename... Args>
explicit Processable(Args&& args):
e( std::forward<Args>(args) ),
myThread( &Engine::processLoopFunction, &e, &e )
{
myThread.detach();
}
};
Now clients create an Engine type with a (non-virtual) processLoopFunction
, then you instantiate a Procesable<T, Engine>
, which automatically does the post-construct work for it. It also perfect forwards the Engine's constructors.
But really, creating a class to do this seems pointless, when all you want is an invokable object. Why not just take an arbitrary type and invoke ()
on it instead of a named processLoopFunction
method?
Similarly, creating thread objects and detaching them is rarely a good idea, as you just made clean shutdown basically impossible.
Upvotes: 0