I'm trying to implement a C++ factory class that also perform the self registration of some derived classes. My implementation is based on the library:
http://arcticinteractive.com/2008/10/06/boost-centric-factory-pattern-implementation/
that is based on the Boost library. Just to give you a quick overview of this library, here is a simple self-explained (I hope) example:
struct foo { virtual ~foo() {} };
struct bar : foo { bar(int i) { std::cout << "bar() " << i << "\n"; } };
struct baz : foo { baz(int i) { std::cout << "baz() " << i << "\n"; } };
...
typedef factory< foo*(int) > myfactory_t;
myfactory_t f;
// Register a default (operator new) creator function
// for an implementation type
register_new_ptr<bar>(f, "bar");
register_new_ptr<baz>(f, "baz");
// Create objects through the factory
foo* fooimpl1 = f["bar"](1234);
foo* fooimpl2 = f["baz"](4321);
What I'm trying to do is to delegate each class to self-register them self to the factory using a static method. Here is the code:
animal.h
#pragma once
#include <cstring>
#include <iostream>
#include "factory.hpp"
#include "abstract_factory.hpp"
class zoo;
using namespace std;
using namespace boost::factory;
class animal{
virtual const std::string do_sound() const = 0;
std::string name_;
int age_;
zoo* myZoo_;
public:
animal(const std::string& name, int age, zoo* myZoo) : name_(name), age_(age), myZoo_(myZoo)
{}
virtual ~animal() {}
const std::string sound() const
{
return do_sound();
}
const std::string& name() const { return name_; }
const int age() const { return age_; }
};
template <class T>
struct animalFactory{
typedef factory< animal*(std::string&, int, zoo*) > myfactory_t;
static const myfactory_t* f;
static bool registerAnimal(const std::string& animalname){
return register_new_ptr<T>(&f, animalname);
};
};
When I try to register a class like:
crocodile.cpp
#include "crocodile.h"
bool r = animalFactory<crocodile>::registerAnimal("crocodile");
I get an error from visual studio 2012 that is:
animal.h(41): error C2893: Failed to specialize function template 'bool boost::factory::register_new_ptr(Factory &,Factory::id_param_type)'
Could someone help me to understand what is going on here? Thanks a lot!
Related
I've been trying to implement the Self Registering Factory pattern in my project and, after trying a bunch of ways to do it, I've settled for this solution.
Unfortunately, I've stumbled upon a problem where my code isn't compiling because my base class doesn't have any arguments to pass. There is a comment in the provided link detailing this exact issue but I must say that I don't understand why it doesn't work and how to make it work if possible.
Here is the error I get when compiling:
could not convert ‘std::make_unique(_Args&& ...) [with _Tp = ObjectA; _Args = {}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<ObjectA, std::default_delete<ObjectA> >]()’ from ‘unique_ptr<ObjectA,default_delete<ObjectA>>’ to ‘unique_ptr<BaseClass,default_delete<BaseClass>>’
40 | return std::make_unique<T>(std::forward<Args>(args)...);
| ^
| |
| unique_ptr<ObjectA,default_delete<ObjectA>>
For the sake of clarity, I'll post the code and example of classes I'm trying to implement with it.
selfregisteringfactory.h
#include <memory>
#include <unordered_map>
#include <string>
#include <cstdlib>
#include <cxxabi.h>
std::string demangle(const char *name) {
int status = -4;
std::unique_ptr<char, void (*)(void*)> res{
abi::__cxa_demangle(name, NULL, NULL, &status), free};
return (status == 0) ? res.get() : name;
}
template<class Base, class... Args>
class SelfRegisteringFactory {
public:
template<class ... T>
static std::unique_ptr<Base> make(const std::string &name, T&&... args) {
return data().at(name)(std::forward<T>(args)...);
}
friend Base;
template <class T>
class Registrar : Base {
friend T;
static bool registerT() {
const auto name = demangle(typeid(T).name());
SelfRegisteringFactory::data()[name] = [](Args... args) -> std::unique_ptr<Base> {
return std::make_unique<T>(std::forward<Args>(args)...);
};
return true;
}
static bool registered;
private:
Registrar() : Base(Key{}) { (void)registered;};
};
private:
class Key {
Key(){};
template <class T> friend class Registrar;
};
using FuncType = std::unique_ptr<Base> (*)(Args...);
SelfRegisteringFactory() = default;
static std::unordered_map<std::string, FuncType> &data(){
static std::unordered_map<std::string, FuncType> s;
return s;
}
};
template <class Base, class... Args>
template <class T>
bool SelfRegisteringFactory<Base, Args...>::Registrar<T>::registered =
SelfRegisteringFactory<Base, Args...>::Registrar<T>::registerT();
baseclass.h
#include "selfregisteringfactory.h"
#include <string>
class BaseClass : public SelfRegisteringFactory<BaseClass>{
public:
BaseClass(Key){};
virtual ~BaseClass() = default;
virtual void process() = 0;
virtual std::string getType() = 0;
};
objecta.h
#include "baseclass.h"
class ObjectA: public BaseClass::Registrar<ObjectA>{
public:
ObjectA();
virtual ~ObjectA() = default;
virtual void process();
virtual std::string getType();
};
objecta.cpp
#include "objecta.h"
#include <iostream>
ObjectA::ObjectA(){
}
void ObjectA::process(){
std::cout << "This is a process." << std::endl;
}
std::string ObjectA::getType(){
return "ObjectA";
}
Update
As #AlanBirtles pointed out, I've missed the public when writting the Registrar class. The code compiles but when I test it with my unit tests it doesn't seems to register ObjectA. I'm getting the out-of-range exception from the .at().
Here's what my test file looks like:
selfregisteringfactory.test.cpp
#include "catch2/catch.hpp"
#include "catch/fakeit.hpp"
#include "baseclass.h"
using namespace fakeit;
TEST_CASE( "TEST SelfRegisteringFactory class." )
{
SECTION("Test if adding an OjbjectA to the factory is possible.")
{
auto objA = DeviceCommunication::make("ObjectA");
REQUIRE(objA ->getType() == "ObjectA");
}
}
why gcc 9.4 not check parameters when bind a class member funtion to a std::function viriable, but check when bind a global function? here is example code, CreateRpcFun has a parameter, but Test member function print doesn't have any other parameters except this, bind print to CreateRpcFun works well, but global funtion print2 cannot, can anybody explain why?
#include <functional>
#include <iostream>
#include <string>
using namespace std;
using CreateRpcFun = std::function<void(const string &)>;
class Test {
public:
Test() : str_("nihao!") {}
// bind print to CreateRpcFun passed compile
void print() { cout << str_ << endl; }
private:
string str_;
};
class Holder {
public:
CreateRpcFun CreateRpc;
};
class Other {
public:
Other(Holder h, string str) : h_(h), str_(str) {}
void run() { h_.CreateRpc("world!"); }
private:
Holder h_;
string str_;
};
void print1(const string &str) { cout << str << endl; }
void print2() { cout << "magic" << endl; }
int main() {
Test t;
Holder h;
h.CreateRpc = std::bind(&Test::print, &t);
Other o(h, "hhhh");
o.run();
h.CreateRpc = &print1;
h.CreateRpc("test");
// h.CreateRpc = &print2; // compile error
// h.CreateRpc("test");
}
I am trying to initialize objects from other classes in my constructor as shared pointers. I need a shred pointer because I need a reference to use in another method in ...
header
class MyClass
{
public:
MyClass() ;
~MyClass() {};
void myMethod();
private:
std::shared_ptr<dds::pub::Publisher>m_pub;
std::shared_ptr<dds::domain::DomainParticipant>m_part;
};
cpp
MyClass::MyClass()
{
m_part = std::make_shared<dds::domain::DomainParticipant>(domain::default_id());
m_pub = std::make_shared<dds::pub::Publisher>(m_part);
}
MyClass::myMethod()
{
//m_part, m_pub are used here
}
what am I missing here?
Error C2039 'delegate': is not a member of 'std::shared_ptr<dds::domain::DomainParticipant>'
dds::pub::Publisher
namespace dds
{
namespace pub
{
typedef dds::pub::detail::Publisher Publisher;
}
}
Publisher
namespace dds { namespace pub { namespace detail {
typedef
dds::pub::TPublisher<org::eclipse::cyclonedds::pub::PublisherDelegate> Publisher;
} } }
PublisherDelegate
namespace dds { namespace pub { namespace detail {
typedef
dds::pub::TPublisher<org::eclipse::cyclonedds::pub::PublisherDelegate> Publisher;
} } }
class OMG_DDS_API PublisherDelegate : public
org::eclipse::cyclonedds::core::EntityDelegate
{
public:
typedef ::dds::core::smart_ptr_traits< PublisherDelegate >::ref_type ref_type;
typedef ::dds::core::smart_ptr_traits< PublisherDelegate >::weak_ref_type weak_ref_type;
PublisherDelegate(const dds::domain::DomainParticipant& dp,
const dds::pub::qos::PublisherQos& qos,
dds::pub::PublisherListener* listener,
const dds::core::status::StatusMask& event_mask);
TPublisher
template <typename DELEGATE>
class dds::pub::TPublisher : public dds::core::TEntity<DELEGATE>
{
public:
typedef dds::pub::PublisherListener Listener;
public:
OMG_DDS_REF_TYPE_PROTECTED_DC(TPublisher, dds::core::TEntity, DELEGATE)
OMG_DDS_IMPLICIT_REF_BASE(TPublisher)
TPublisher(const dds::domain::DomainParticipant& dp);
TPublisher(const dds::domain::DomainParticipant& dp,
const dds::pub::qos::PublisherQos& qos,
dds::pub::PublisherListener* listener = NULL,
const dds::core::status::StatusMask& mask = dds::core::status::StatusMask::none());
I tried the method given in answer got new error,
Error C2672 'std::dynamic_pointer_cast': no matching overloaded function in TPublisher.hpp
I guess m_pub should be initialised like this
m_pub = std::make_shared<dds::pub::Publisher>(*m_part);
The class dds::pub::Publisher a.k.a. dds::pub::TPublisher has the constructor taking const dds::domain::DomainParticipant by reference.
The answer is changed after the question has been updated.
I already asked about my Problem, now I'm on the next Step. In the code below I have the Problem, that I always have to make the EventHandler (Server::HandleMessage) static. But I need to have it non static to access other Variables in the Server class from within the Handler.
How can I achieve this?
Here my Code:
#include <iostream>
#include <functional>
using namespace std;
class Client{
public:
struct MessageReceiveArgs {
MessageReceiveArgs(int ID, const std::string& Text) : ID(ID), Text(Text) {}
int ID;
std::string Text;
};
std::function<void(MessageReceiveArgs)> onMessageReceive;
Client(){}
void FireEvent(){
this->onMessageReceive(MessageReceiveArgs(16, "SomeText"));
}
};
class Server{
public:
int i;
Server(){
this->client.onMessageReceive = &Server::HandleMessage;
this->i = 5;
}
void FireEvent(){
this->client.FireEvent();
}
Client client;
static void HandleMessage(Client::MessageReceiveArgs args) {
std::cout<<"ID "<<args.ID<<": "<<" "<<args.Text<<std::endl;
//need it non static
//std::cout<<"I: "<<this->i<<std::endl;
}
};
int main() {
Server sv = Server();
sv.FireEvent();
}
As mentioned in my earlier Post, i'm new to Standard C++ (Unix).
I'm fairly sure this is what you're after. You need to bind the implicit this explicitly when invoking a pointer-to-member through std::function in the fashion you seem to desire.
#include <iostream>
#include <functional>
using namespace std;
class Client{
public:
struct MessageReceiveArgs
{
MessageReceiveArgs(int ID, const std::string& Text)
: ID(ID), Text(Text) {}
int ID;
std::string Text;
};
Client(){}
void FireEvent()
{
this->onMessageReceive(MessageReceiveArgs(16, "SomeText"));
}
std::function<void(MessageReceiveArgs)> onMessageReceive;
};
class Server
{
public:
int i;
Server()
{
this->client.onMessageReceive
= std::bind(&Server::HandleMessage, this, std::placeholders::_1);
this->i = 5;
}
void FireEvent()
{
this->client.FireEvent();
}
Client client;
void HandleMessage(Client::MessageReceiveArgs args)
{
std::cout<<"ID "<<args.ID<<": "<<" "<<args.Text<<std::endl;
}
};
int main()
{
Server sv = Server();
sv.FireEvent();
}
Output
ID 16: SomeText
I have made a map of functions. all these functions are void and receive single string parameter.
code:
void f1(string params){...}
void f2(string params){...}
void f3(string params){...}
map<string , void*> funcMap;
funcMap["f1"] =(void*)&f1;
funcMap["f2"] =(void*)&f2;
funcMap["f3"] =(void*)&f3;
how do i call a function?
I tried the next code, but id doesn't work:
void (*func)(string) = &funcMap[commandType];
func(commandParam);
I get this error message:
Server.cpp:160:46: error: cannot convert ‘void**’ to ‘void (*)(std::string) {aka void (*)(std::basic_string<char>)}’ in initialization
using pfunc = void (*)(string);
map<string, pfunc> funcMap;
funcMap["f1"] = f1; //and so forth
And then call:
pfunc f = funcMap[commandType];
(*f)(commandParam);
In general, why throw away type safety? If it's a map of function pointers, declare it to be one.
Why not just have those as separate classes.
Then have the methods as virtual.
You can then have a map between the string and the base class.
i.e.
class Someoperation
{
virtual void Doit() = 0;
};
map<string, Someopertion> ops;
Then
class MyOp : public Someoperation
{
void Doit() { /* Some code here */}
};
Just add objects
ops["Hello"] = MyOp();
then call it
ops["Hello"].Doit();
&funcMap[commandType]
Just drop the &. Your compile error was useful here. It had a void** on the right which is because you took the address of a function pointer. You don't want two levels of indirection there.
Try C++ style. It has overhead for allocation and inheritance, but it's more flexible and extensible if you'll need some more functionality in the future.
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
using namespace std;
class Someoperation {
public:
virtual void Doit() = 0;
};
class MyOp1 : public Someoperation {
public:
void Doit() final { cout << "MyOp1" << endl; }
};
class MyOp2 : public Someoperation {
public:
void Doit() final { cout << "MyOp2" << endl; }
};
int main() {
unordered_map<string, unique_ptr<Someoperation> > ops;
ops["1"] = unique_ptr<Someoperation>(new MyOp1);
ops["2"] = unique_ptr<Someoperation>(new MyOp2);
ops["1"]->Doit(); // Out: MyOp1
ops["2"]->Doit(); // Out: MyOp2
return 0;
}