How to Instantiate Objects from a String Holding Their Class Name

Is there a way to instantiate objects from a string holding their class name?

Nope, there is none, unless you do the mapping yourself. C++ has no mechanism to create objects whose types are determined at runtime. You can use a map to do that mapping yourself, though:

template<typename T> Base * createInstance() { return new T; }

typedef std::map<std::string, Base*(*)()> map_type;

map_type map;
map["DerivedA"] = &createInstance<DerivedA>;
map["DerivedB"] = &createInstance<DerivedB>;

And then you can do

return map[some_string]();

Getting a new instance. Another idea is to have the types register themself:

// in base.hpp:
template<typename T> Base * createT() { return new T; }

struct BaseFactory {
typedef std::map<std::string, Base*(*)()> map_type;

static Base * createInstance(std::string const& s) {
map_type::iterator it = getMap()->find(s);
if(it == getMap()->end())
return 0;
return it->second();
}

protected:
static map_type * getMap() {
// never delete'ed. (exist until program termination)
// because we can't guarantee correct destruction order
if(!map) { map = new map_type; }
return map;
}

private:
static map_type * map;
};

template<typename T>
struct DerivedRegister : BaseFactory {
DerivedRegister(std::string const& s) {
getMap()->insert(std::make_pair(s, &createT<T>));
}
};

// in derivedb.hpp
class DerivedB {
...;
private:
static DerivedRegister<DerivedB> reg;
};

// in derivedb.cpp:
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");

You could decide to create a macro for the registration

#define REGISTER_DEC_TYPE(NAME) \
static DerivedRegister<NAME> reg

#define REGISTER_DEF_TYPE(NAME) \
DerivedRegister<NAME> NAME::reg(#NAME)

I'm sure there are better names for those two though. Another thing which probably makes sense to use here is shared_ptr.

If you have a set of unrelated types that have no common base-class, you can give the function pointer a return type of boost::variant<A, B, C, D, ...> instead. Like if you have a class Foo, Bar and Baz, it looks like this:

typedef boost::variant<Foo, Bar, Baz> variant_type;
template<typename T> variant_type createInstance() {
return variant_type(T());
}

typedef std::map<std::string, variant_type (*)()> map_type;

A boost::variant is like an union. It knows which type is stored in it by looking what object was used for initializing or assigning to it. Have a look at its documentation here. Finally, the use of a raw function pointer is also a bit oldish. Modern C++ code should be decoupled from specific functions / types. You may want to look into Boost.Function to look for a better way. It would look like this then (the map):

typedef std::map<std::string, boost::function<variant_type()> > map_type;

std::function will be available in the next version of C++ too, including std::shared_ptr.

Create object from class name using a string in C++

Variadic template is a template, which can take an arbitrary number of template arguments of any type. Both the functions could be variadic since dawn of C language (printf function, for example), then macros and now - templates.

You can declare it like this:

template<typename... Arguments> class Variadic;

then specialize it with any number of arguments, including zero:

Variadic<double> instance;
Variadic<double, std::string> instance;
Variadic<> instance;

Then you may use the argument list, known as argument pack, like this:

template<typename... Arguments> void SampleFunction(Arguments... parameters);

Just as in case of variadic functions, the argument pack can be preceded by concrete arguments:

template<typename First, typename... Rest> class BunchOfValues;

There is classic example of variadic template in STL: std::tuple. Some compilers do not support this feature fully or do not support at all, and in their case tuple is implemented through metaprogramming and macro definitions.
There is no direct way in C++ to select particular argument from the list, like it is possible with variadic functions. It's possible to use recursion to iterate through them in one direction:

template<typename T> foo(T first)
{
// do something;
}

template<typename T, typename U, typename ... Args> foo(T first, U second, Args... Rest)
{
// do something with T
foo(second, Rest...);
}

Usually iteration would rely on function overloading, or - if the function can simply pick one argument at a time - using a dumb expansion marker:

template<typename... Args> inline void pass(Args&&...) {}

which can be used as follows:

  template<typename... Args> inline void expand(Args&&... args) {
pass( some_function(args)... );
}

expand(42, "answer", true);

which will expand to something like:

 pass( some_function(arg1), some_function(arg2), some_function(arg3) etc... );

The use of this "pass" function is necessary, since the expansion of the argument pack proceeds by separating the function call arguments by commas, which are not equivalent to the comma operator. some_function(args)...; will never work. Moreover, this above solution will only work when the return type of some_function is not void. Furthermore, the some_function calls will be executed in an unspecified order, because the order of evaluation of function arguments is undefined. To avoid the unspecified order, brace-enclosed initializer lists can be used, which guarantee strict left-to-right order of evaluation. To avoid the need for a not void return type, the comma operator can be used to always yield 1 in each expansion element.

  struct pass {
template<typename ...T> pass(T...) {}
};

pass{(some_function(args), 1)...};

The number of arguments in argument pack can be determined by sizeof...(args) expression.

As of creating initializers that use calls name it is possible only if name is defined at time of writing the code. There stingizer operator # in preprocessor that can be used, e.g.

#define printstring( x ) printf(#x "\n")

printstring( This a dumb idea );

will generate code (assuming that C++ automatically joins string literals):

printf("This a dumb idea \n")

You can declare something like this:

template<typename T> class moniker
{
public:
moniker(const char* tname);
}

#define declare_moniker(type, name) moniker<type> name(#type)

How would variadic macro definitions and variadic template interact? I'm not sure. Compiler I have at hand failed, but it isn't C++11. Try that, if interested.

There might be typeid operator supporeted, depending on compiler settings.

const std::type_info& ti1 = typeid(A);

std::type_info got method name(), but string it returns is implementation dependant: http://en.cppreference.com/w/cpp/types/type_info/name

Instantiate class from name?

This is a problem which is commonly solved using the Registry Pattern:

This is the situation that the
Registry Pattern describes:

Objects need to contact another
object, knowing only the object’s name
or the name of the service it
provides, but not how to contact it.
Provide a service that takes the name
of an object, service or role and
returns a remote proxy that
encapsulates the knowledge of how to
contact the named object.


It’s the same basic publish/find model
that forms the basis of a Service
Oriented Architecture (SOA) and for
the services layer in OSGi.

You implement a registry normally using a singleton object, the singleton object is informed at compile time or at startup time the names of the objects, and the way to construct them. Then you can use it to create the object on demand.

For example:

template<class T>
class Registry
{
typedef boost::function0<T *> Creator;
typedef std::map<std::string, Creator> Creators;
Creators _creators;

public:
void register(const std::string &className, const Creator &creator);
T *create(const std::string &className);
}

You register the names of the objects and the creation functions like so:

Registry<I> registry;
registry.register("MyClass", &MyClass::Creator);

std::auto_ptr<T> myT(registry.create("MyClass"));

We might then simplify this with clever macros to enable it to be done at compile time. ATL uses the Registry Pattern for CoClasses which can be created at runtime by name - the registration is as simple as using something like the following code:

OBJECT_ENTRY_AUTO(someClassID, SomeClassName);

This macro is placed in your header file somewhere, magic causes it to be registered with the singleton at the time the COM server is started.

How create an object of a Class from a string that holds the name of that class?

There is nothing in C++ that will provide you such feature (called Reflection).

However, if your classes are of finite number, you can do some kind of mapping with some factories :

class IClassFactory // base interface
{ public:
virtual ~IClassFactory(){}
}

template< class T >
class ClassFactory {
/* whatever necessary here*/
public:

T* create();
};


class ClassManager
{
public:

void add( std::string name, IClassFactory* factory ) { m_map[name] = factory; }

ACommonBaseClass* create( std::string class_name ) { return m_map[class_name]->create(); } // this line isn't correct but you get the idea

private:

std::map< std::string, IClassFactory* > m_map;

};

Or something similar (this is written quickly).

Alternatively you could work with a scripting language that would allow Reflection, but that would add a whole layer to your application. Scripting languages that might be of interest for embedding with c++ : ChaiScript, Falcon, Lua, Python, AngelScript, MonkeyScript, Io, ...

How to instantiate objects whose constructor requires parameters from a string holding the class name?

I'm going to preface this by saying, maybe C++ isn't the right language for whatever you're trying to accomplish. The more you try to control your program via external data, the closer you get to full on scripting. And there are lots of more powerful options when that is your goal.

That said, sure, it is possible, although not as easily. Two ways come immediately to mind. The first is to require all applicable types to have a constructor that accepts a std::string. This constructor will be responsible for its own parsing.

template<typename T> Base * createInstance(const std::string& s) { return new T(s); }
typedef std::map<std::string, Base*(*)(const std::string&)> map_type;
//...and similar changes as needed

If you don't want to change your type definitions, or this is otherwise unacceptable [perhaps your types already have such a constructor?], get rid of the templated createInstance method, and provide individual versions for each type you are interested in. This function does the parsing, and calls the appropriate constructor.

map["derivedA"] = createDerivedA;
map["derivedB"] = createDerivedB;

A third option might be possible using variadic templates [or boost-esque variadic-like templates] that would bring you back to the original simplicity.

template<typename T, typename... Args>
Base* create(std::string) {
//somehow pass the string to a generic function that packs the arguments into a tuple
//then somehow unpack that tuple and pass the bits to the constructor
}

map["derivedA"] = create<derivedA, int, double, std::string>;

However, I have no idea how to pull that off, or even if it is possible.

Instantiation of class by classname

You can always store std::function<Base*()> as you always return pointers to Base from your create function:

class Base {};

class DerivedA : public Base {};
class DerivedB : public Base {};
class DerivedC : public Base {};

Base* create(const std::string& type)
{
static std::map<std::string, std::function<Base*()>> type_creator_map =
{
{"DerivedA", [](){return new DerivedA();}},
{"DerivedB", [](){return new DerivedB();}},
{"DerivedC", [](){return new DerivedC();}}
};

auto it = type_creator_map.find(type);
if(it != type_creator_map.end())
{
return it->second();
}

return nullptr;
}

As Angew suggested, you should return std::unique_ptr instead of raw pointers. If the user of create function wants a raw pointer or a std::shared_ptr he/she can just "grab" the raw pointer and use it.

UPDATE:

Next method provides a convenient semi-automatic way of registering new types without changing old code.

I don't recommend using it because it depends on the linker (the moment of creating global variables might be delayed), they way you compile the code(executable, static library, dynamic library), it allocates memory before main() starts and it creates weird named global variables.

Use it only if you really know what you are doing and know on what platforms you are using the code!

class Base {};

std::map<std::string, std::function<Base*()>>& get_type_creator_map()
{
static std::map<std::string, std::function<Base*()>> type_creator_map;
return type_creator_map;
}

template<typename T>
struct RegisterTypeHelper
{
RegisterTypeHelper(const std::string& id)
{
get_type_creator_map()[id] = [](){return new T();};
}
};

Base* create(const std::string& type)
{
auto& type_creator_map = get_type_creator_map();
auto it = type_creator_map.find(type);
if(it != type_creator_map.end())
{
return it->second();
}

return nullptr;
}

#define RegisterType(Type) static RegisterTypeHelper<Type> register_type_global_##Type(#Type)

class DerivedA : public Base {};
RegisterType(DerivedA);

class DerivedB : public Base {};
RegisterType(DerivedB);

class DerivedC : public Base {};
RegisterType(DerivedC);

Instantiate Kotlin class from string

Instantiating classes by String name is more error-prone than using a constructor, because it relies on using a fully qualified, correctly spelled name, and the class having a specific constructor (either empty, or with specific arguments). So it can be done, but should be avoided when there are safer ways of doing it (ways where the compiler will give you an error if you're doing it wrong, instead of having an error occur only after you run the compiled program).

If I understand correctly, you want a list of classes that will only be instantiated one-at-a-time at random. One way to do this would be to make a list of class constructors.

val classConstructors = listOf<() -> Any>(
::ClassA,
::ClassB,
::ClassC
)

val randomInstantiatedClass = classConstructors.random()()


Related Topics



Leave a reply



Submit