I've been experimenting with the factory implementation described here:
http://www.nirfriedman.com/2018/04/29/unforgettable-factory/
The example uses "Animal" as a base and "Dog" and "Cat" as the derived classes that are registered with the factory. But now suppose I wanted to add a "Lion" class that derives from Cat... how can I derive from Cat while still registering with the Animal factory? Further, I would like to be able to create a "Cat" factory as well that would let me create object of type "Cat" instead of "Animal". Can this example be adapted to do this?
Here is some code based off the original post that shows what I'm trying to do.
#include <functional>
#include <memory>
#include <exception>
#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <cstdlib>
#include <cxxabi.h>
template<typename BaseT, typename ...Args>
class Factory
{
public:
friend BaseT;
template<class ...T>
static std::shared_ptr<BaseT> create(const std::string& name, T&&... args)
{
try
{
return types().at(name)(std::forward<T>(args)...);
}
catch(std::out_of_range e)
{
throw std::runtime_error("type \"" + name + "\" is not registered with the factory");
};
};
template<typename T>
struct Registrar : BaseT
{
public:
friend T;
static bool register_type()
{
auto demangle = [](const char* name) -> std::string
{
int status = -4;
std::unique_ptr<char, void (*)(void *)> res{abi::__cxa_demangle(name, NULL, NULL, &status), free};
return (status == 0) ? res.get() : name;
};
const auto name = demangle(typeid(T).name());
std::cout << "registering " << name << "\n";
Factory::types()[name] = [](Args... args) -> std::shared_ptr<BaseT>
{
return std::make_shared<T>(std::forward<Args>(args)...);
};
return true;
};
static inline bool registered = register_type();
private:
Registrar() : BaseT() { (void) registered; };
};
private:
using FunctionT = std::function< std::shared_ptr<BaseT>(Args...)>;
static auto& types()
{
static std::unordered_map<std::string, FunctionT> m_types;
return m_types;
};
};
struct Animal : Factory<Animal>
{
virtual void speak() = 0;
virtual ~Animal() = default;
};
// How can I create a Cat factory at this level in the hierarchy?
class Cat : public Animal::Registrar<Cat>
{
public:
Cat() {};
virtual ~Cat() = default;
virtual void speak() { std::cout << "Meow!" << "\n"; };
};
// I would like to register Lion with the Animal factory.
class Lion : public Cat
{
public:
Lion() {};
void speak() { std::cout << "Roar!" << "\n"; };
};
int main(int argc, char** argv)
{
auto a = Animal::create("Cat");
a->speak();
auto lion = Cat::create("Lion"); // this doesn't work
lion->speak();
return 0;
};
I ended up tweaking the factory class slightly by remove inheritance from Base in the Registrar class. I changed this:
template <class T> struct Registrar : Base {
to this:
template <class T> struct Registrar
Going back to my example above I now use the factory like so:
struct Animal
{
virtual void speak() = 0;
virtual ~Animal() = default;
};
using AnimalFactory = Factory<Animal>;
struct Cat : public Animal, public AnimalFactory::Registrar<Cat>
{
<snip>
};
struct Lion : public Cat, public AnimalFactory::Registrar<Lion>
{
<snip>
};
The main difference is that now each class has to derive from an Animal class or sub-class as well as the AnimalFactory::Registrar type. It's a little more verbose but I now have the ability to use the factory with multiple levels of inheritance.
Related
I see this question has been discussed in various places, e.g. here,here,here and here .But, i have still not been able to relate to the questions aforementioned.
My situation:
I am trying to implement a simple generic visitor pattern in C++. The hosts in this pattern are different pets, these are in a file called Pet.h. The visitors are in a separate header called Visitors.h.
The concrete Pet classes accept, generic visitor classes(See Comment 0 in Pet.h), and the generic visitor classes visits the generic Pet classes. So, there is a natural cyclic dependency.
Earlier, when all the code was in a single header, there were no problems. Now there is. To illustrate, here is the Pet.h class.
P.S: I am using Visual Studio 2017.
#pragma once
#include <string>
#include "Visitors.h"
namespace pet
{
class Pet {
public:
virtual ~Pet() {}
virtual void accept(temp_visitor::PetVisitor& v) = 0; //Comment 0 Pet accepts a gneric PetVisitor
virtual std::string getAnimal() = 0;
private:
std::string color_;
};
template <typename Derived>
class Visitable : public Pet {
public:
using Pet::Pet;
Visitable() = default;
Visitable(const std::string& animal) : animal_(animal) {}
void accept(temp_visitor::PetVisitor& v) override {
v.visit(static_cast<Derived*>(this));
}
std::string getAnimal() override
{
return animal_;
}
std::string animal_;
};
class Cat : public Visitable<Cat> {
using Visitable<Cat>::Visitable;
};
class Dog : public Visitable<Dog> {
using Visitable<Dog>::Visitable;
};
}
And here is the Visitors.h file. The void visit(pet::Pet* p) gives the following error "use of undefined type pet::Pet on using p->getAnimal()
#include<iostream>
#pragma once
namespace pet
{
class Pet; //Comment 1. Attempted forward declaration.
}
namespace temp_visitor
{
template <typename ... Types>
class Visitor;
template <typename T>
class Visitor<T> {
public:
virtual void visit(T* t) = 0;
};
using PetVisitor = Visitor<pet::Pet>;
class FeedingVisitor : public PetVisitor {
public:
void visit(pet::Pet* p) override { std::cout << "Feed veggies to the "+ p->getAnimal() << std::endl; } //Comment 2: Gives the following error "use of undefined type pet::Pet"
};
}
So how do i fix this problem ?
You need to move the FeedingVisitor to a new header and cpp as well. In header you will have #include "Visitors.h", forward declration for Pet and in cpp #include "Pet.h"
Something like
Visitors.hpp
namespace pet {
class Pet; //Comment 1. Attempted forward declaration.
}
namespace temp_visitor
{
template <typename ... Types> class Visitor;
template <typename T> class Visitor<T>
{
public:
virtual void visit(T* t) = 0;
};
}
FeedingVisitor.hpp
#include "Visitors.h"
namespace temp_visitor
{
using PetVisitor = Visitor<pet::Pet>;
class FeedingVisitor : public PetVisitor {
public:
void visit(pet::Pet* p) override; // only declaration
};
}
FeedingVisitor.cpp
// move the definition to cpp
void temp_visitor::FeedingVisitor::visit(pet::Pet* p) {
std::cout << "Feed veggies to the " + p->getAnimal() << std::endl;
}
I am trying to understand the behavior of "Type Erasure" by using std::make_shared. The basic idea is to use a class Object to wrap some different classes, such as class Foo and class Bar.
I write the following code, and it does work.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
struct Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
but when I change "struct Derived : Base" into "class Derived : Base", it shows the following error.
error: no matching function for call to 'std::shared_ptr::shared_ptr(std::shared_ptr)'|
The code is as following.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
class Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
What is the root cause of this error?
Is it about the difference between class and struct?
Is it because class is a reference and struct is a value?
The only real difference between a class and a struct in C++ is that, for a struct, the default member access and inheritance is public, whereas, for a class, the default is private.
So, to make your code work for the class Derived template, just make its inheritance of Base public:
template< typename T >
class Derived : public Base { // public inheritance
public:
//...
Such public inheritance gives the Derived class access to the Base class constructors.
Alternatively, to make your struct template case fail – most likely with the exact same error message(s) – you can make its inheritance of Base private:
template< typename T >
struct Derived : private Base { // private inheritance - fails to compile!
public:
//...
Is there anyway to get a type from a static base class method? For instance
class A
{
static std::type_info getClassType
{
// What do I do here
}
};
class B : public A
{
};
B instance;
auto my_type = instance::getClassType()
With C++'s lack of static variable overloading, I am having a hard time figuring out a way to determine class type across classes without doing a special virtual function in every child class which I am trying to avoid due to the sheer number.
Make a class that will be a template.
Subclass from it. Pass the child type as the template parameter.
With that, base class will know the child. The T will be the child type.
Code:
#include <iostream>
using namespace std;
template<typename T> class thebase
{
static T instance;
public:
static T& getInstance() { return instance; }
};
template <typename T> T thebase<T>::instance;
class sub1 : public thebase<sub1> {
public: void tell() { std::cout << "hello1: " << this << std::endl; }
};
class sub2 : public thebase<sub2> {
public: void tell() { std::cout << "hello2: " << this << std::endl; }
};
int main() {
sub1& ref1 = sub1::getInstance();
sub1& ref2 = sub1::getInstance();
std::cout << ((&ref1) == (&ref2)) << std::endl;
sub1::getInstance().tell();
sub2::getInstance().tell();
sub1::getInstance().tell();
sub2::getInstance().tell();
return 0;
}
Output:
1
hello1: 0x55874bff1193
hello2: 0x55874bff1192
hello1: 0x55874bff1193
hello2: 0x55874bff1192
This kind of code pattern is sometimes called CRTP
it boils down to there being a manager class that keeps track of one instance of a variety of classes and their states. You may use this singleton "instance" of these sub classes, but I want to be able to say MySubClass::instance() and then have it get the correct instance from the manager without having to write it in each sub class.
You can implement the managed classes using CRTP ("Curiously recurring template pattern") so a base class knows the derived class types and can then delegate that information to the manager class.
Try something like this:
#include <map>
#include <typeinfo>
#include <typeindex>
class Base {
public:
virtual ~Base() {}
};
class Manager
{
private:
static std::map<std::type_index, Base*> m_instances;
public:
template<typename T>
static void addInstance(Base *inst) {
if (!m_instances.insert(std::make_pair(std::type_index(typeid(T)), inst)).second)
throw ...; // only 1 instance allowed at a time!
}
template<typename T>
static void removeInstance() {
auto iter = m_instances.find(std::type_index(typeid(T)));
if (iter != m_instances.end())
m_instances.erase(iter);
}
template<typename T>
static T* getInstance() {
auto iter = m_instances.find(std::type_index(typeid(T)));
if (iter != m_instances.end())
return static_cast<T*>(iter->second);
return nullptr;
}
};
std::map<std::type_index, Base*> Manager::m_instances;
template<class Derived>
class A : public Base
{
public:
A() {
Manager::addInstance<Derived>(this);
}
~A() {
Manager::removeInstance<Derived>();
}
static Derived* getInstance() {
return Manager::getInstance<Derived>();
}
};
class B : public A<B>
{
...
};
class C : public A<C>
{
...
};
B b_inst;
C c_inst;
...
B *pB = B::getInstance();
if (pB) ...
C *pC = C::getInstance();
if (pC) ...
Live Demo
Based on your own example of code in your own answer, here's a final result working:
# include <iostream>
# include <typeinfo>
template <class T>
class A
{
public:
static const std::type_info& getClassType()
{
return typeid(T);
}
};
class B : public A<B>
{ /* ... */ };
class C : public A<C>
{ /* ... */};
class D : public A<D>
{ /* ... */};
int main()
{
B b; C c; D d;
auto& b_type = b.getClassType();
auto& c_type = c.getClassType();
auto& d_type = d.getClassType();
std::cout << b_type.name() << std::endl;
std::cout << c_type.name() << std::endl;
std::cout << d_type.name() << std::endl;
}
Output:
1B 1C 1D
Someone above mentioned the CRTP or "Curiously recurring template pattern". Using this, I have not tested it, but it appears I may be able to write:
template <class T>
class A
{
static std::type_info getClassType
{
return typeid(T);
}
};
class B : public A<B>
{
};
B instance;
auto my_type = instance::getClassType()
Suppose we have a base class and a bunch of derived classes. Is there any way or mechanism to know all the derived class names programmatically?
Maybe reflection is a good idea, but it's not available on C++. I suppose there will be some kind of template that can finish this job during compilation.
class Base{
public:
virtual void print(){
// This function should print all the names of derived class.
}
virtual Base* getInstance(string class_name){
// This function should return an instance related to the class name.
}
};
class Derived_1 : public Base{ // Suppose we have 100 Derived_X classes,
// so we don't want to add its name to a list manually.
};
int main(){
Base base;
base.print(); // This should print the name of all the derived class.
base.getInstance("Derived_1"); // This should return an instance of Derived_1
return 0;
}
This solution is based on the fact that it seems you are actually looking for a factory. It uses a small macro to ease classes registration, hope you don't care about it.
factory.h
#ifndef __FACTORY_H__
#define __FACTORY_H__
#include <map>
#include <functional>
#include <string>
#include <iostream>
template<class B>
class Factory {
std::map<std::string, std::function<B*()>> s_creators;
public:
static Factory<B>& getInstance() {
static Factory<B> s_instance;
return s_instance;
}
template<class T>
void registerClass(const std::string& name) {
s_creators.insert({name, []() -> B* { return new T(); }});
}
B* create(const std::string& name) {
const auto it = s_creators.find(name);
if (it == s_creators.end()) return nullptr; // not a derived class
return (it->second)();
}
void printRegisteredClasses() {
for (const auto &creator : s_creators) {
std::cout << creator.first << '\n';
}
}
};
#define FACTORY(Class) Factory<Class>::getInstance()
template<class B, class T>
class Creator {
public:
explicit Creator(const std::string& name) {
FACTORY(B).registerClass<T>(name);
}
};
#define REGISTER(base_class, derived_class) \
Creator<base_class, derived_class> s_##derived_class##Creator(#derived_class);
#endif
example.cpp
#include "factory.h"
#include <memory>
class Base {
public:
virtual void printName() const { std::cout << "Base\n"; }
};
class Derived1 : public Base {
public:
virtual void printName() const override { std::cout << "Derived1\n"; }
};
REGISTER(Base, Derived1);
class Derived2 : public Base {
public:
virtual void printName() const override { std::cout << "Derived2\n"; }
};
REGISTER(Base, Derived2);
int main() {
std::cout << "Registered classes:" << std::endl;
FACTORY(Base).printRegisteredClasses();
std::cout << "---" << std::endl;
std::unique_ptr<Base> derived1(FACTORY(Base).create("Derived1"));
derived1->printName();
return 0;
}
Note: requires C++11.
For the getInstance you can declare it a template (needs C++14). To get all the names of the derived classes in the program you probably have to resort to some preprocessor hack.
#include <type_traits>
class Base
{
public:
virtual ~Base () = default;
template < typename T,
typename = std::enable_if_t<std::is_base_of<Base, T>::value, void>
>
T getInstance() { return T{}; }
};
class Derived : public Base {};
class NotDerived {};
int main(){
Base base;
base.getInstance<Derived>();
// error: no matching member function for call to 'getInstance'
//base.getInstance<NotDerived>();
}
Regarding the name of the derived classes, I propose a solution based on a BaseList class/struct, with a static std::set (or other container) of names, a template Base class/struct, that inherit from BaseList and whose template parameter is the derived class (CRTP style) and (to semplify the construction of the derived classes/struct, a C-style macro (I know... macros are distilled evil... but sometimes...) to create the declaration of the derived classes/structs with a necessary static method, that declare the name of the derived class/struct, and a member (that activate the registration of the name).
The following is a full example (unfortunately is a C++11 one)
#include <set>
#include <string>
#include <iostream>
struct BaseList
{
static std::set<std::string> const & derList (std::string const & dn)
{
static std::set<std::string> dl;
if ( dn.size() )
dl.insert(dn);
return dl;
}
static void print ()
{
std::cout << "derived names: ";
for ( auto const & dn : derList("") )
std::cout << dn << ", ";
std::cout << std::endl;
}
};
template <typename Der>
struct Base : public BaseList
{
static std::size_t setNameInList ()
{ return derList(Der::name()).size(); }
static std::size_t id;
};
template <typename Der>
std::size_t Base<Der>::id = setNameInList();
#define setDerived(nameDer) \
struct nameDer : public Base<nameDer>\
{ \
std::size_t idc { id }; \
static std::string name () \
{ return #nameDer; }
setDerived(Derived_1)
// other elements
};
setDerived(Derived_2)
// other elements
};
setDerived(Derived_3)
// other elements
};
int main()
{
BaseList::print();
}
Regarding the getInstance() problem, the only solution that I can imagine is the same solution proposed by Enry Menke (+1), so I suggest that you get the instance through a template type parameter.
I try to implement the Visitor pattern with templated derived classes
I work with gcc 4.5
here is the VisitorTemplate.hpp, I specialized Derived in the class Visitor, but I'd like to be able to handle any type:
edit : thanks to the suggestions of interjay, the code compiles and runs without errors now
#ifndef VISITORTEMPLATE_HPP_
#define VISITORTEMPLATE_HPP_
#include <iostream>
#include <string>
using namespace std;
template<class T> Derived;
class Visitor
{
public:
virtual void visit(Derived<string> *e) = 0;
};
class Base
{
public:
virtual void accept(class Visitor *v) = 0;
};
template<class T>
Derived: public Base
{
public:
virtual void accept(Visitor *v)
{
v->visit(this);
}
string display(T arg)
{
string s = "This is : " + to_string(arg);
return s;
}
};
class UpVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Up on " + e->display("test") << '\n';
}
};
class DownVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Down on " + e->display("test") << '\n';
}
};
#endif /* VISITORTEMPLATE_HPP_ */
main.cpp
Base* base = new Derived<string>();
Visitor* up = new UpVisitor();
Visitor* down = new DownVisitor();
base->accept(up);
base->accept(down);
Now my goal is to use Derived in visit without specializing; unfortunately, visit is a virtual method so I can't template it
From Modern C++ - Design Generic Programming and Design Patterns Applied - Andrei Alexandrescu
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T, typename R = int>
class Visitor
{
public:
virtual R visit(T &) = 0;
};
template <typename R = int>
class BaseVisitable
{
public:
typedef R ReturnType;
virtual ~BaseVisitable() {};
virtual ReturnType accept(BaseVisitor & )
{
return ReturnType(0);
}
protected:
template <class T>
static ReturnType acceptVisitor(T &visited, BaseVisitor &visitor)
{
if (Visitor<T> *p = dynamic_cast< Visitor<T> *> (&visitor))
{
return p->visit(visited);
}
return ReturnType(-1);
}
#define VISITABLE() \
virtual ReturnType accept(BaseVisitor &v) \
{ return acceptVisitor(*this, v); }
};
/** example of use */
class Visitable1 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class Visitable2 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1, int>,
public Visitor<Visitable2, int>
{
public:
int visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept(visitor);
visitable2.accept(visitor);
}
Is possible to avoid dynamic_cast with CRTP pattern like:
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T>
class Visitor
{
public:
virtual void visit(T &) = 0;
};
template <class Visitable>
class BaseVisitable
{
public:
template <typename T>
void accept(T & visitor)
{
visitor.visit(static_cast<Visitable &>(*this));
}
};
/** example of use */
class Visitable1 : public BaseVisitable<Visitable1>
{
};
class Visitable2 : public BaseVisitable<Visitable2>
{
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1>,
public Visitor<Visitable2>
{
public:
void visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept<VisitorDerived>(visitor);
visitable2.accept<VisitorDerived>(visitor);
}
Your Derived class cannot use Visitor because it hasn't been defined yet (it was only forward declared, and is therefore an incomplete type).
You can fix the compile error by putting the Visitor definition before Derived. You will also need to forward-declare Derived before defining Visitor:
template <class T> class Derived;
class Visitor {
public:
virtual void visit(Derived<string> *e) = 0;
};
template <class T>
class Derived : public Base {
//.... can call Visitor methods here ...
};