0

sorry for the title, it's quite confusing to explain, but it will be more clear with example

In C, I used to write program like this :

void createClassA()
{
}

void createClassB()
{
}

typedef struct {
        const char *name;
        void (*create_class)();
} MapList;

MapList mapList[] = {
        {"A", &createClassA},
        {"B", &createClassB },
};

void create(const char *name)
{
        int i=0;
        for (i=0; i < sizeof(mapList) / sizeof(MapList); i++) {
                if (strcmp(name, mapList[i].name) == 0) mapList[i].create_class();
        }
}

int main(int argc, char** argv)
{
        if (argc < 1) return -1;
        create(argv[1]);

        return 0;
}

So if I have more types, all I have to do is to create the function itself and add it to the mapList.

but in C++, the best I can do is something like:

#include <iostream>

class myA{};
class myB{};
class myC{};

class Base
{
public:
        template<class T>
        void createClass()
        {
                T* t = new T();
                //t->doSomethingUseful();
        }

        void create(const std::string name)
        {
                if (name=="A") createClass<myA>();
                else if (name=="B") createClass<myB>();
                else if (name=="C") createClass<myC>();
        }
};

int main(int agrc, char** argv)
{
        if (argc<1) return -1;
        Base b;
        b.create(argv[0]);

        return 0;
}

Can I create something like :

typedef struct {
   std::string name;
   [CLASS_TYPE] class_type; <== I don't know how
} MapList;

so I can create a mapping List but fill it with class Type, something like

mapList[] = {
   {"A", myA},
   {"B", myB},
   {"B", myC},
};

and then I can create iteration like:

for (int i=0; i<sizeof(mapList) / sizeof(MapList); i++) {
   if (mapList[i].name == name) b.createClass<mapList[i].classType>();
}

Thanks guys :)

4 Answers 4

2

In C++ you can use std::function in the <functional> standard header. Specifically, your example for the map list can be written as (with lambdas):

std::map<std::string, std::function<void()>> mapList;
mapList["A"] = []() { /* ... */ };
mapList["B"] = []() { /* ... */ };

or just (without lambdas):

void createClassA() {}
void createClassB() {}

std::map<std::string, std::function<void()>> mapList;
mapList["A"] = createClassA;
mapList["B"] = createClassB;
Sign up to request clarification or add additional context in comments.

Comments

1

In C++ you could do that with virtual functions:

struct ClassMaker {
    virtual void create_class() = 0;
};
struct ClassMakerA : public ClassMaker {
    virtual void create_class() {
        ...
    }
};
struct ClassMakerB : public ClassMaker {
    virtual void create_class() {
        ...
    }
};

Now you can create a std::map<std::string,ClassMaker*> with your "factories", like this:

ClassMakerA makerA;
ClassMakerB makerB;
// This syntax requires C++11
std::map<std::string,ClassMaker*> makers = {
    {"A", &makerA}
,   {"B", &makerB}
};

Finally, you can now call create_class() based on a std::string value, like this:

void create(const std::string &name) {
    ClassMaker *maker = makers[name];
    if (maker) maker -> create_class();
}

Comments

0

You could look for Boost::any, which provides "a variant value type".

5 Comments

@H2CO3 Why would you refuse using Boost? Plus any is header-only, it's not even part of the must-be-built parts of Boost...
Why would you use a huge, bloated 3rd-party library, when the standard library (or even core language features) can do what you want?
@H2CO3 Why not ? If you're using C++, Boost contains a hell lot of features, and is considered the antichamber of the standard lib. It would be dumb not to use it if it can be of use, instead of reinventing the wheel (when it implies a huge chunk of code, or not-so-trivial implementations), in a probably worse version than Boost's. And in this case, it provides the feature in a single header, not even needing linking. Then, I think discussion about it may end up being futile, as there'll always be people who seems to need to reinvent the wheel.
Just one thing, Boost is the jQuery of C++. I'm done. (I don't deny that it's useful, but sometimes it's just not worth using.)
@H2CO3 I disagree. Boost isn't the jQuery of C++. You can take a tiny part of Boost without needing the whole lib (let alone even linking, in this case...). Conceptually, I could agree, it may sometimes not be worth using if you're really sure that you can implement quickly a specific feature that could come from Boost. Personnally I'd go as far as saying Boost and jQuery are quite completely unrelated (languages apart).
0

You can use derived classes and object factory, something like that would work. You can improve it by make create method to return smart pointers and make A and B constructors private to avoid creating objects on the stack.

class Base
{
static Base* create(const char *name);
};

class A : public Base
{
};

class B : public Base
{

};

Base* Base::create(const char *name)
{
if(strcmp(name,"A")==0)
return new A();
if(strcmp(name,"B")==0)
return new B();

return 0;
}

int main(int agrc, char** argv)
{
        if (argc<1) return -1;
        Base *b = Base::create(argv[0]);

        return 0;
}

It is somewhat similar to solution by @dasblinkenlight, but avoid virtual functions overhead.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.