I have several classes named Child1, Child2 ... etc, inherited from object Parent. I need to create an object by its name, for example if I have string "Child1", I need to create object Child1 and so on.
I thought about something like:
struct registry_entry {
const char* name;
IREGISTRY* (*initializer)();
};
struct registry_entry registry_list[] =
{
{"xml", ®ISTRY_XML::REGISTRY_XML},
}
But I can't get address of object constructor.I believe that this problem must be already solved, and the solution is pretty simple, but I can't find it.
Constructors and destructors are special functions and cannot be accessed through function pointers.
You need to create a static member function like
struct REGISTRY_XML {
static IREGISTRY* create();
};
thus you can refer to it as
struct registry_entry registry_list[] =
{
{"xml", ®ISTRY_XML::create},
}
Your code looks very C-like and not very C++-like, but if you can actually use the full power of C++11, I would go with a combination of std::function, lambdas, std::unique_ptr and std::map.
Lambdas can wrap constructors without you having to write separate wrapper functions, std::function allows you to store the lambdas in a map, std::unique_ptr eliminates many memory-management bugs, and std::map performs the actual mapping from strings to initialiser functions.
Here is a complete example:
#include <functional>
#include <string>
#include <memory>
#include <map>
#include <iostream>
struct IREGISTRY {
virtual ~IREGISTRY() {}
virtual void print() = 0;
};
struct REGISTRY_XML : IREGISTRY { void print() override { std::cout << "XML\n"; } };
struct REGISTRY_INI : IREGISTRY { void print() override { std::cout << "INI\n"; } };
struct REGISTRY_JSON : IREGISTRY { void print() override { std::cout << "JSON\n"; } };
int main()
{
std::map<std::string, std::function<std::unique_ptr<IREGISTRY>()>> const registry_list = {
{ "xml", []() { return std::make_unique<REGISTRY_XML>(); } },
{ "ini", []() { return std::make_unique<REGISTRY_INI>(); } },
{ "json", []() { return std::make_unique<REGISTRY_JSON>(); } },
};
auto const initializer_iter = registry_list.find("xml");
if (initializer_iter != registry_list.end())
{
auto const initializer = initializer_iter->second;
auto const registry_ptr = initializer();
registry_ptr->print();
}
}
Related
I have several classes that each of them has an ID and the Id is passed to the class as a template parameter:
typedef class1<1> baseClass;
typedef class2<2> baseClass;
typedef class<100> baseClass;
Now I need a map so if I can associate 1 with Class1 and 2 with Class2 and so on.
How can I create such vector? I am working on a header only library, so it should be a header only definition.
I am looking something that do the same thing that this code would do (if someone can compile it!):
std::map<int,Type> getMap()
{
std::map<int,Type> output;
output.add(1,class1);
output.add(2,class2);
output.add(100,class100);
}
The idea is that when I get as input 1, I create a class1 and when I receive 2, I create class2.
Any suggestion is very appreciated.
using this data, then I can write a function like this:
void consume(class1 c)
{
// do something interesting with c
}
void consume(class2 c)
{
// do something interesting with c
}
void consume(class3 c)
{
// do something interesting with c
}
void consume(int id,void * buffer)
{
auto map=getMap();
auto data= new map[id](buffer); // assuming that this line create a class based on map, so the map provide the type that it should be created and then this line create that class and pass buffer to it.
consume(data);
}
As a sketch:
class BaseClass { virtual ~BaseClass() = default; };
template<std::size_t I>
class SubClass : public BaseClass {};
namespace detail {
template<std::size_t I>
std::unique_ptr<BaseClass> makeSubClass() { return { new SubClass<I> }; }
template<std::size_t... Is>
std::vector<std::unique_ptr<BaseClass>(*)> makeFactory(std::index_sequence<Is...>)
{ return { makeSubclass<Is>... }; }
}
std::vector<std::unique_ptr<BaseClass>(*)> factory = detail::makeFactory(std::make_index_sequence<100>{});
We populate the vector by expanding a parameter pack, so we don't have to write out all 100 instantiations by hand. This gives you Subclass<0> at factory[0], Subclass<1> at factory[1], etc. up to Subclass<99> at factory[99].
If I understand correctly you want a map to create different types according to a given number.
If that is so, then the code should look something like this:
class Base
{
};
template <int number>
class Type : public Base
{
public:
Type()
{
std::cout << "type is " << number << std::endl;
}
};
using Type1 = Type<1>;
using Type2 = Type<2>;
using Type3 = Type<3>;
using CreateFunction = std::function<Base*()>;
std::map<int, CreateFunction> creators;
int main()
{
creators[1] = []() -> Base* { return new Type1(); };
creators[2] = []() -> Base* { return new Type2(); };
creators[3] = []() -> Base* { return new Type3(); };
std::vector<Base*> vector;
vector.push_back(creators[1]());
vector.push_back(creators[2]());
vector.push_back(creators[3]());
}
output:
type is 1
type is 2
type is 3
If you need only to create object, it would be enough to implement template creator function like:
template<int ID>
Base<ID> Create()
{
return Base<ID>();
}
And then use it:
auto obj1 = Create<1>();
auto obj2 = Create<2>();
// etc
Working example: https://ideone.com/urh7h6
Due to C++ being a statically-typed language, you may choose to either have arbitrary types that do a fixed set of things or have a fixed set of types do arbitrary things, but not both.
Such limitations is embodied by std::function and std::variant. std::function can have arbitrary types call operator() with a fixed signature, and std::variant can have arbitrary functions visit the fixed set of types.
Since you already said the types may be arbitrary, you may only have a fixed set of things you can do with such a type (e.g. consume). The simplest way is to delegate the hard work to std::function
struct Type
{
template<typename T>
Type(T&& t)
: f{[t = std::forward<T>(t)]() mutable { consume(t); }} {}
std::function<void()> f;
};
void consume(Type& t)
{
t.f();
}
What you are looking for is either the Stategy pattern:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class A {
public:
A() {}
virtual void doIt() {};
};
class Aa : public A {
public:
Aa() {}
virtual void doIt() {
std::cout << "do it the Aa way" << std::endl;
}
};
class Ab : public A {
public:
Ab() {}
virtual void doIt() {
std::cout << "do it the Ab way" << std::endl;
}
};
class Concrete {
public:
Concrete(std::string const& type) {
if (type == ("Aa")) {
_a.reset(new Aa());
} else if (type == "Ab") {
_a.reset(new Ab());
}
}
void doIt () const {
_a->doIt();
}
private:
std::unique_ptr<A> _a;
};
int main() {
std::vector<Concrete> vc;
vc.push_back(Concrete("Aa"));
vc.push_back(Concrete("Ab"));
for (auto const& i : vc) {
i.doIt();
}
return 0;
}
Will output:
do it the Aa way
do it the Ab way
Is possible create a queue for differents types of Objects, but with same interface?
As example, I have an interface called SensorItem, and 4 kinds of Class, SensorItemA
,SensorItemB,
SensorItemC
,SensorItemD
`
queue <SensorItem> cola;
void encolar(SensorItem* dato)
{
cola.push (*dato);
}
SensorItem* sacar()
{
SensorItem* d=cola.front();
cola.pop();
return d;
}
Thats my class Queue(Cola)
and here i try to use it
void main()
{
Cola c=new Cola();
TemperatureItem t=new TemperatureItem(3.25);
c.encolar(t);
ImuItem i=new ImuItem(3,4,8);
}
its something wrong in my syntax? or just is not possible to do it?
Polymorphism in C++ only works with references and pointers. Objects in C++ are objects, not references. If you create a SensorItem it will always be a SensorItem, not a TemperatureItem or a ImuItem. If you have a std::queue<SensorItem>, it's elements will always be SensorItems, never TemperatureItems or ImuItems.
If you want to make a queue of objects derived from SensorItem, you need to use a queue of pointers to SensorItems:
#include <iostream>
#include <queue>
#include <memory>
struct SensorItem
{
virtual void doAThing() = 0;
virtual ~SensorItem() {}
};
struct TemperatureItem : SensorItem
{
void doAThing() { std::cout << "TemperatureItem\n"; }
};
struct ImuItem : SensorItem
{
void doAThing() { std::cout << "ImuItem\n"; }
};
class Cola
{
private:
std::queue<std::unique_ptr<SensorItem>> cola;
public:
void encolar(std::unique_ptr<SensorItem> dato)
{
cola.push(std::move(dato));
}
std::unique_ptr<SensorItem> sacar()
{
std::unique_ptr<SensorItem> d = std::move(cola.front());
cola.pop();
return d;
}
};
int main()
{
Cola c;
c.encolar(std::make_unique<TemperatureItem>());
c.encolar(std::make_unique<ImuItem>());
std::unique_ptr<SensorItem> item = c.sacar();
item->doAThing();
item = c.sacar();
item->doAThing();
}
Live on Coliru
Here I've used std::unique_ptr to avoid having to do manual memory management. You could use raw SensorItem*s, but I would advise against it.
I have the following code:
struct A
{
const string name;
A(string name) :name(name) {}
};
struct Parent
{
public:
const decltype(make_tuple(A("AA"))) children{ make_tuple(A("AA")) };
Parent()
{
}
};
Is it possible to avoid typing A("AA") twice?
Like when you use the auto keyword- but working.
You can move A("AA") or even better make_tuple(A("AA")) into its own function:
namespace {
auto make_children() { return make_tuple(A("AA")); }
}
struct Parent
{
public:
const decltype(make_children()) children{ make_children() };
Parent()
{
}
};
Live example
That way you only need to repeat the name of the helper function twice. Depending on the size/complexity of the expression in your real code, that might be a win.
I have a class that stores weak_ptrs in a container and later does something if the weak_ptr is not expired:
class Example
{
public:
void fill(std::shared_ptr<int> thing)
{
member.push_back(thing);
}
void dosomething() const
{
for (const auto& i : member)
if (!i.expired())
;// do something. the weak_ptr will not be locked
}
private:
std::vector<std::weak_ptr<int>> member;
};
If Example is an object that lives forever and fill is used regularily, the vector allocates memory for elements continously, but they are never removed after they expired.
Is there any automatic C++ way to get rid of the expired weak_ptrs in the container or is there a better way to store a variable number of them?
My naive way would be to iterate over the container each time fill is called and remove all the expired weak_ptrs. In scenarios where Example has many elements in the container and fill is frequently called this seems to be very inefficient.
Since you clarified that you are actually using a std::map and not a std::vector, it might be easiest to remove the expired elements on-the-fly in doSomething(). Switch back from a range-based for loop to a normal iterator based design:
void dosomething() const
{
auto i = member.begin();
while( i != member.end() ) {
if( i->expired() ) { i = member.erase( i ); continue; }
;// do something. the weak_ptr will not be locked
++i;
}
}
Does the shared_ptr<int> have to be a shared_ptr<int>?
How about a shared_ptr<IntWrapper>?
#include <iostream>
#include <forward_list>
using namespace std;
class IntWrapper {
public:
int i;
static forward_list<IntWrapper*>& all() {
static forward_list<IntWrapper*> intWrappers;
return intWrappers;
}
IntWrapper(int i) : i(i) {
all().push_front(this);
}
~IntWrapper() {
all().remove(this);
}
};
void DoSomething() {
for(auto iw : IntWrapper::all()) {
cout << iw->i << endl;
}
}
int main(int argc, char *argv[]) {
shared_ptr<IntWrapper> a = make_shared<IntWrapper>(1);
shared_ptr<IntWrapper> b = make_shared<IntWrapper>(2);
shared_ptr<IntWrapper> c = make_shared<IntWrapper>(3);
DoSomething();
return 0;
}
I would rather use a custom deleter for the shared_ptr. But this implies here to change the interface of the Example class. The advantage using custom deleter is that there is no need to check for expired objects in the collection. The collection is directly maintained by the custom deleter.
Quick implementation :
#include <memory>
#include <iostream>
#include <set>
template <typename Container>
// requires Container to be an associative container type with key type
// a raw pointer type
class Deleter {
Container* c;
public:
Deleter(Container& c) : c(&c) {}
using key_type = typename Container::key_type;
void operator()(key_type ptr) {
c->erase(ptr);
delete ptr;
}
};
class Example {
public:
// cannot change the custom deleter of an existing shared_ptr
// so i changed the interface here to take a unique_ptr instead
std::shared_ptr<int> fill(std::unique_ptr<int> thing) {
std::shared_ptr<int> managed_thing(thing.release(), Deleter<containter_type>(member));
member.insert(managed_thing.get());
return managed_thing;
}
void dosomething() const {
// we don't need to check for expired pointers
for (const auto & i : member)
std::cout << *i << ", ";
std::cout << std::endl;
}
using containter_type = std::set<int*>;
private:
containter_type member;
};
int main()
{
Example example;
auto one = example.fill(std::unique_ptr<int>(new int(1)));
auto two = example.fill(std::unique_ptr<int>(new int(2)));
auto three = example.fill(std::unique_ptr<int>(new int(3)));
example.dosomething();
three.reset();
example.dosomething();
}
I did quite a bit of searching, but the combination of * () and class scope has greatly hindered me in understanding of the syntax, with each edit throwing a new error, any help guys?
What I'm trying to do:
Declare a std::vector of pointers to member functions found in MyClass.h
Assign the actual member functions to the std::vector in MyClass.cpp's constructor
The member functions are not static
Thanks!
I'm curious where you're going to use them from. You see in order to call a C++ class member function you need to have an instance pointer with which to call it (each member function needs a this in order to access the class state). So normally you'd wrap the member function pointer together with the instance pointer with std::bind and then maybe store the result in std::function. To put them in vector they're all going to need the same signature.
Is this the kind of thing you were looking for:
class P
{
typedef std::function<void (void)> func_t;
std::vector<func_t> functions;
public:
P()
{
functions.push_back(std::bind(&P::foo1, this));
functions.push_back(std::bind(&P::foo2, this));
functions.push_back(std::bind(&P::foo3, this));
}
void foo1(void)
{
std::cout << "foo1\n";
}
void foo2(void)
{
std::cout << "foo2\n";
}
void foo3(void)
{
std::cout << "foo3\n";
}
void call()
{
for(auto it = functions.begin(); it != functions.end(); ++it)
{
(*it)();
}
}
};
int main()
{
P p;
p.call();
}
After further clarification from the OP I'll propose this:
class P
{
typedef std::function<void (void)> func_t;
std::map<const char*, func_t> functions;
public:
P()
{
functions["foo1"] = std::bind(&P::foo1, this);
functions["foo2"] = std::bind(&P::foo2, this);
functions["foo3"] = std::bind(&P::foo3, this);
}
void foo1(void)
{
std::cout << "foo1\n";
}
void foo2(void)
{
std::cout << "foo2\n";
}
void foo3(void)
{
std::cout << "foo3\n";
}
void call_by_name(const char* func_name)
{
functions[func_name]();
}
};
int main()
{
P p;
p.call_by_name("foo1");
p.call_by_name("foo2");
p.call_by_name("foo3");
}
You can use member function pointers like this (the C++11 is unrelated to that part):
struct S {
int foo(){std::cout<<"foo"; return 0;}
int bar(){std::cout<<"bar"; return 0;}
};
int main() {
std::vector<int(S::*)()> funcs{&S::foo, &S::bar};
S s;
for (auto func : funcs) {
(s.*func)();
}
}
However, if you use C++11, std::function can make it a bit cleaner:
std::vector<std::function<int(S &)>> funcs{&S::foo, &S::bar};
S s;
for (auto func : funcs) {
func(s);
}
If you use C++03, Boost has boost::function, which is similar.