I have a program which is built on "Entities", which hold "Components" (composition FTW).
Components may include many different types including scripts, assets, etc. I would like to build an Entity function called
Entities have a map of strings, and actual Components, such that the Components can be searched for by type name.
I would like to have a function called
<Component T>GetComponent(char* TypeName, <T>);
Which takes in a string and a type name, and which returns the typed component that is requested.
Is it possible to do such a thing with C++ templates? The above clearly does not work, and I'm not sure how to go about it.
Thanks
Edit:
I'm not looking for a factory.
Entity holds instances of different types of components. Currently this is done with
std::vector<Component> componentList;
and an
std::vector<char*> componentNames;
Whose indexes are guaranteed to be the same. Likely I will write a proper map later.
I simply want GetComponent to return a properly typed reference to the already instantied component of type name held by Entity in the ComponentList.
Does your function create components? Then it is a factory. You could wrap it in that template in order to save clients the (potentially erroneous) casting.
The type of the function template would look like this:
template< typename T >
T* GetComponent(const char*); // presuming it returns a pointer
and it would be called like this:
Foo* foo = GetComponent<Foo>("foo");
Asking the proper question is at least half of the way to getting a good answer. You should really state what you want to achieve rather than the particular problem you are facing. It seems to me as if you have more problems with the language than you actually realize.
The first part is that it seems as if you have a component hierarchy that derives from Component, probably providing a common interface. An entity holds many components internally, that can be of any derived type from Component. If that is the case, you should rework your containers as you are storing Component objects directly, and that will produce slicing in your objects (no matter what derived type you enter into the container, the container will only keep the common Component part of the object).
Working on a couple of vectors and hoping that both of them will be synchronized at all times is feasible but fragile. If the name and the component go together, then you want to store pairs of name/component. If you want to search by name, you should use a map as it will provide O(log N) search directly.
Now, going back to the question. If what you want to achieve is plain syntactic sugar (avoid the caller from explicitly dynamic casting if needed) then you can get it with a template (more later on). But you should really think on your design. Does Component define the real interface into any component? If users need to downcast to particular types before using a Component, either the abstraction is bad (Component does not provide a real interface) or the objects do not really fit together.
If at the end of it you still want to do it, you can hide the dynamic cast from the caller by doing it within a template method (or free function).
class Entity {
typedef std::map< std::string, boost::shared_ptr<Component> > component_map_t;
public:
boost::shared_ptr<Component> getComponent( std::string const & name ) {
component_map_t::iterator it = components_.find(name);
if ( it == components_.end() ) { // not found, handle error
// ...
}
return it->second;
}
template <typename T> // syntactic sugar
boost::shared_ptr<T> getComponent( std::string const & name ) {
return boost::dynamic_pointer_cast<T>( getComponent(name) );
}
private:
component_map_t components_;
};
template <typename T> // syntactic sugar also available as free function
boost::shared_ptr<T> getComponent( Entity & entity, std::string const & name ) {
return boost::dynamic_pointer_cast<T>( entity.getComponent(name) );
}
int main() { // usage
Entity e; // ... work with it add components...
boost::shared_ptr<Component> c1 = e.getComponent( "one" ); // non-templated method returns Component
boost::shared_ptr<DerivedComponent> c2 = e.getComponent<DerivedComponent>( "two" );
boost::shared_ptr<DerivedComponent> c3 = getComponent<DerivedComponent>( e, "two" );
}
You could play with the interface so that instead of boost::shared_ptr you return real references (with what it entails: lifetime must be carefully controlled so that user code does not try to use a dangling reference if the component is removed from the entity).
You could use something like:
struct Entity
{
Component* GetBaseComponent (const char* TypeName)
{
// do lookup on TypeName and return corresponding Component.
}
template<typename T> T* GetComponent (const char* TypeName)
{
return dynamic_cast<T*> (GetBaseComponent (TypeName));
}
};
and call it with something like:
entity.GetComponent<MyComponent> ("MyComponent");
If you ask for a component and get the type wrong the cast will return a null ptr.
Edit: Just realised this is essentially the same solution as sbi, albeit without calling it a factory.
Your getComponent function has two separate tasks
1) retrieve an object from a string identifier
2) cast this object into the provided template argument type
Using templates makes (2) pretty straight forward. But (1) needs work on string objects, so templates won't do the trick on their own. You have got to fill your component container some other way. As for storing and casting, you may be interested in boost::any or boost::variant.
Related
I am trying to implement a C++ class which will wrap a value (among other things). This value may be one of a number of types (string, memory buffer, number, vector).
The easy way to implement this would be to do something like this
class A {
Type type;
// Only one of these will be valid data; which one will be indicated by `type` (an enum)
std::wstring wData{};
long dwData{};
MemoryBuffer lpData{};
std::vector<std::wstring> vData{};
};
This feels inelegant and like it wastes memory.
I also tried implementing this as a union, but it came with significant development overhead (defining custom destructors/move constructors/copy constructors), and even with all of those, there were still some errors I encountered.
I've also considered making A a base class and making a derived class for each possible value it can hold. This also feels like it isn't a great way to solve the problem.
My last approach would be to make each member an std::optional, but this still adds some overhead.
Which approach would be the best? Or is there another design that works better than any of these?
Use std::variant. It is typesafe, tested and exactly the right thing for a finite number of possible types.
It also gets rid of the type enum.
class A {
std::variant<std::wstring, long, MemoryBuffer, std::vector<std::wstring>> m_data{}; // default initializes the wstring.
public
template<class T>
void set_data(T&& data) {
m_data = std::forward<T>(data);
}
int get_index() { // returns index of type.
m_data.index();
}
long& get_ldata() {
return std::get<long>(m_data); // throws if long is not the active type
}
// and the others, or
template<class T>
T& get_data() { // by type
return std::get<T>(m_data);
}
template<int N>
auto get_data() { // by index
return std::get<N>(m_data);
}
};
// using:
A a;
a.index() == 0; // true
a.set_data(42);
a.index() == 1; // true
auto l = a.get<long>(); // l is now of type long, has value 42
a.get<long>() = 1;
l = a.get<1>();
PS: This example does not even include the coolest (in my opinion) feature of std::variant: std::visit I am not sure what you want to do with your class, so I cannot create a meaningful example. If you let me know, I will think about it.
You basically want QVariant without the rest of Qt, then :)?
As others have mentioned, you could use std::variant and put using MyVariant = std::variant<t1, t2, ...> in some common header, and then use it everywhere it's called for. This isn't as inelegant as you may think - the specific types to be passed around are only provided in one place. It is the only way to do it without building a metatype machinery that can encapsulate operations on any type of an object.
That's where boost::any comes in: it does precisely that. It wraps concepts, and thus supports any object that implements these concepts. What concepts are required depends on you, but in general you'd want to choose enough of them to make the type usable and useful, yet not too many so as to exclude some types prematurely. It's probably the way to go, you'd have: using MyVariant = any<construct, _a>; then (where construct is a contract list, an example of which is as an example in the documentation, and _a is a type placeholder from boost::type_erasure.
The fundamental difference between std::variant and boost::any is that variant is parametrized on concrete types, whereas any is parametrized on contracts that the types are bound to. Then, any will happily store an arbitrary type that fulfills all of those contracts. The "central location" where you define an alias for the variant type will constantly grow with variant, as you need to encapsulate more type. With any, the central location will be mostly static, and would change rarely, since changing the contract requirements is likely to require fixes/adaptations to the carried types as well as points of use.
I have a abstract component class and an entity class with a vector full of components (the derived possibilities). I want to be able to lookup components. Is it better to look them up by type or by string?
ComponentA* component = entity.getComponent<ComponentA>();
// vs
ComponentA* component = entity.getComponent( "ComponentA" );
In both instances I'll need a vtable, but only in the later will I need to implement some sort of getName function for every derived class.
Consider this declaration:
template<typename T>
T * getComponent();
Different Ts, different return types and you can assign the returned value directly to a variable of the right type.
It could work. So far so good.
Now consider this declaration:
?? getComponent(std::string);
Or this one if you prefer:
?? getComponent (const char *);
What should be the return type? The best you can do is to use a common base class of your components (if any exists) and cast it within the context of the caller each and every time. I cannot imagine anything more annoying actually.
The other way around you can use it is by returning a void * but I discourage it.
You can even add a second parameter that is a callable object to which you pass the right type (overload operator() or make it a template), but it will make everything a bit more confusing at the call point.
Otherwise you can make your function a template one to set at the call point directly the return type but... Wait... Aren't we turning towards the first case? Add the template parameter, remove the function parameter for it's redundant now and what you get is:
template<typename T>
T * getComponent();
I'd say that this is already enough to decide what's the best bet.
So I have a resource manager that is basically a dictionary of void* objects that have some metadata describing their type (basic metadata like a string). I have a template method right now that returns an object:
class ResourceManager
{
template<typename Type>
Type RetrieveResource( Text name );
};
My question is how can I make this method not a template method? I've done some research into trailing return types and using that funky syntax. The idea is that at some point I have the data as the correct type and I want to return it as that type without additional casting on the end user's part.
I'm shooting for something like this:
auto RetrieveResource( Text name)
{
return _dictionary[ name ]; // There's more to this, but imagine it returns varying type objects.
}
I've given some thought to implementing a Boost::Any type of object, but it's kind of complicated (not that I'm lazy). I'm trying to avoid template syntax on the end user's part.
Any help would be great. Also I cannot use Boost library structures like variant or any (project specs). Thanks in advance!
I understand I'm kind of asking for magic here, but I figured that's what S/O is for: finding magic. If it's not possible, I understand. But if someone has an innovative solution, that would be awesome.
In addition to the other answers, you could do something like this, assuming that every Text key corresponds uniquely to a resource with a known, different Type:
class BaseText
{
// constructors that take const char *, std::string, etc.
// .. whatever else you currently have in class Text
};
template<typename Type>
class Text : public BaseText
{
// constructors that take const char *, std::string, etc.
};
Then change ResourceManager to be:
class ResourceManager
{
template<typename Type>
Type RetrieveResource( Text<Type> name );
};
Note this still requires compile-time polymorphism, but means that as long as your user can obtain the correctly-typed version of Text<Type>, they can use it to obtain the correctly typed resource without having to explicitly provide the Type argument again, so it'll look like a normal function call.
This works easily if the set of possible Text<Type> objects can be statically declared and initialized with the right types, which I'm not sure is true in your case. If, instead, the user must be able to create them at runtime, though, they'll need to know the correct type to create, so it just pushes the problem back a bit further: however, it might be convenient enough if the same Text<Type> object is going to be used over and over again.
Note that you're also out of luck if you or the client need to store different Text<Type> objects together in some kind of data structure, since that will require some sort of type erasure (i.e. upcasting to BaseText). So this is somewhat of a specialized solution but it's possible it could be useful, depending on how things are structured (I really can't know without seeing more of your code).
EDIT: As per the comment below, it seems like the type of the object is determined by the client when they insert an object, so you could possibly do something like this:
class ResourceManager
{
BaseText PutResource( const BaseText& name, BaseResource& resource );
template<typename Type>
Text<Type> PutResource( const BaseText& name, Type& resource );
BaseResource& RetrieveResource( const BaseText& name );
template<typename Type>
Type& RetrieveResource( const Text<Type>& name );
};
So the client is required to hold on to the unique typed key object in order to retrieve the resource later; if they choose to type erase it by upcasting it back to BaseText, then they'll be responsible for recovering the type information correctly, either by downcasting the key before retrieval or downcasting the resource afterwards.
Note that this is just an extra option on top of what you will have to do anyway: if you want to provide access to resources using a non-type-specific key, the only way to do so is by returning a non-specific resource type (i.e. BaseResource, boost::any, boost::variant<...>, or one of their moral equivalents.) However, creating a type-specific subclass of BaseText allows you to obtain a correctly typed resource, using the exact same syntax (i.e. with no explicit template parameter required). Furthermore, this allows the following usage:
// tree is a resource of type `Tree`
auto key = manager.PutResource("Tree01", tree);
// ...
const BaseText& basekey = key; // lose type information
// ...
// these are all equivalent
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource("Tree01"));
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource(basekey));
Tree& tree = manager.RetrieveResource(key); // no casts required
Tree& tree = manager.RetrieveResource<Tree>("Tree01")
The dynamic_cast versions are basically what you'll need to do without these templated overloads, but the others two versions are extra options on top of that that you can use with this approach without any runtime cost.
I'm afraid that would be to ambiguous. You can't overload by return type and you can't use auto as the return type.
I think, that the best choice will be returning some base class pointer. The minus is that you force anyone to derive from it, but with smart architecture of base class there could be more pluses
I'm new to C++, and unfortunately I cannot stop thinking in C# (my former language).
I read some books, forums and the C++ reference website, but I couldn't find an answer to my question, so I thought I might as well try here before giving up and writing something ugly.
Ok, we can start.
I have a class with an abstract method succesorsFunction and I would like it to return a collection of pointers to State. I don't want to force the implementors to a specific container; I rather let them choose (vector, list, etc).
So it looks like this:
class Problem
{
public:
virtual list<const State*>::iterator succesorsFunction(const State &state, list<const State*>::iterator result) const = 0;
};
the problem here is the explicit use of list. How do you do it in C++?
I thought about using templates, but then I encountered two problems:
1) It seems like you cannot do it with abstract methods (or am I wrong?)
2) How do I tell the template it should contain pointers to State?
You can't overload methods based on return types in C++.
Also, "containers" in C++ don't have the same base (like Collection in Java), so you can't return a generic container.
I'm afraid there's no clean way of doing this.
I would just write overloads (by parameter) or different function names.
For your questions:
1) You can. What makes you think you can't?
2) The same way you declared list: list<const State*> - const is optional.
If you really want to enforce STL container usage, try the following:
template <template <typename,
typename = std::allocator<const State *> > class Container>
Container<const State*> successorsFunction(const State &state, const Container<const State*> &c) const
{
// return something useful.
}
If you insist on having this function be virtual, then it can't be a member function template, just overload it with the types you intend to support, then you can make them virtual.
You can't have a member function template which is virtual, but you can try implement friend generic function like this:
template <typename yourType>
yourType& succesorsFunction(const State &a, yourType &result){//Your return type can be without reference
//Your body
return result;
}
If you call your function for example with vector<State> a argument like this:
sucessorsFunction(b,a);// b is your State object
deduction process will automatically conclude that yourType is actually vector<State> type, which I think resolves your problem. Also, this arhitecture aloves you to create for example new class type MyVector (which holds arrays of States) and pass MyVector object to succesorsFunction.
This is just an elaboration to C.T's answer. Please remember that if you return a container of pointers then you will have to release them explicitly or use std::unique_ptr .
Just a FYI.. as you are from C# background.
You could use State or templatize it as well.
template<typename Type,
template< typename, typename = std::allocator<Type*> > class Container
>
Container<Type*> Successor(const Type& x)
{
Container<Type*> cont;
// something.
cont.push_back(new Type(x));
return cont;
}
and call it
vector<State*> states = Successor<State, vector>(State(10));
I am considering a factory function to create different classes in the same hierarchy. I understand that normally a factory is normally implemented as follows:
Person* Person::Create(string type, ...)
{
// Student, Secretary and Professor are all derived classes of Person
if ( type == "student" ) return new Student(...);
if ( type == "secretary" ) return new Secretary(...);
if ( type == "professor" ) return new Professor(...);
return NULL;
}
I am trying to think of a way so that the process can be automated so that the various conditions do not need to be hard-coded.
So far the only way I can think of is using a map and the prototype pattern:
The map will hold the type string in the first element and a class instance (prototype) in the second:
std::map<string, Person> PersonClassMap;
// This may be do-able from a configuration file, I am not sure
PersonClassMap.insert(make_pair("student", Student(...)));
PersonClassMap.insert(make_pair("secondary", Secretary(...)));
PersonClassMap.insert(make_pair("professor", Professor(...)));
The function may look something like this:
Person* Person::Create(string type)
{
map<string, Person>::iterator it = PersonClassMap.find(type) ;
if( it != PersonClassMap.end() )
{
return new Person(it->second); // Use copy constructor to create a new class instance from the prototype.
}
}
Unfortunately, the prototype method only works if you only want the class created by the factory to be identical every time, since it does not support arguments.
Does anybody know if it is possible to do it in a nice way, or am I stuck with the factory function?
I usually build a factory method (or a factory object) when the clients will be providing some information about the object to be created, but they don't know what concrete class the result will be. The determination about how to express the interface to the factory depends completely on what information the clients have. It could be that they provide a string (program text to be parsed, for example), or a set of parameter values (number of dimensions and sizes if we're creating geometric objects in n-space). The factory method then examines the information and decides what kind of object to create or which more specific factory to call.
So the decision about what to build shouldn't be made by the caller; if she knows, then there's no reason for a factory. If the list of things to be built is open-ended, you might even have a registration protocol that allows specific implementations to provide both their construction method and a discriminator function that would allow the factory method to decide which method to call.
It very much depends on what information is necessary and sufficient to decide which kind of object to build.
You can register a factory method (instead of the prebuilt element to copy). This will allow you to call the abstract factory with parameters that are passed to the concrete factory. The limitation here is that the set of parameters of all concrete factories must be the same.
typedef std::string discriminator;
typedef Base* (*creator)( type1, type2, type3 ); // concrete factory, in this case a free function
typedef std::map< discriminator, creator > concrete_map;
class Factory // abstract
{
public:
void register_factory( discriminator d, creator c ) {
factories_[ d ] = c;
}
Base* create( discriminator d, type1 a1, type2 a2, type3 a3 )
{
return (*(factories_[ d ]))( a1, a2, a3 );
}
private:
concrete_map factories_;
};
I have used free function creators to reduce the sample code, but you can define a concrete_factory type and use it instead of the 'creator' element above. Again, as you can see, you are limited to a fixed set of arguments in the factory 'create' method.
Each concrete factory can pass the arguments to the constructor of the given type:
Base* createDerived1( type1 a1, type2 a2, type3 a3 )
{
return new Derived1( a1, a2, a3 );
}
This is more flexible than your approach as you can create instances that hold references to external objects (those can only be initialized during construction) or constant members, or objects that cannot be reset to a different state after construction in a more general wording.
I would add a pure abstract clone method to class Person (which definitely looks like it should be an abstract class, existing mainly for the sake of being subclassed -- if you need a concrete "none of the above" kind of Person it's best done via a separate concrete subclass OtherKindOfPerson, rather than as the base class itself):
virtual Person* clone() const = 0;
and override it in every concrete subclass, e.g. in Student, with a new that invokes the specific concrete subclass's copy ctor:
Person* clone() const { return new Student(*this); }
You also need to change the registry map to:
std::map<string, Person*> PersonClassMap;
[[You could use some smarter pointer than a plain old Person *, but as the map and all of its entries probably needs to survive as long as the process does, this is definitely not a big deal -- the main added value you might get from smarter pointers being smarter behavior upon destruction of the "pointer"!-)]]
Now, your factory function can simply end with:
return it->second->clone();
The changes are needed to avoid the "slicing" effect of using the base class's copy ctor on a subclass that has extra attributes, as well as preserve any virtual method's resolution.
Subclassing a concrete class to yield other concrete classes is a bad idea exactly because these effects can be tricky and a source of bugs (see Haahr's recommendation against it: he writes about Java, but the advice is also good for C++ and other languages [indeed I find his recommendation even more crucial in C++!].
I am not familar with c++ but in many langugaes there concepts of delegates or closures. Means that instead of mapping to instance, you map to the function(delegate, closure) that is responsible to create object.
You could make an enum of each type of person:
enum PersonType { student, secretary, professor };
Well if you want a faster way to do it then using an enum and a switch statement will be many time faster than processing sequential if/else if statements ...
If you look at your two implementations, logically they are identical.
The first implementation is the same as your second if the recursive loop was unrolled. So really there is no advantage of your second implementation.
Regardless what you do you will need to list some where your types mapped to your constructors.
One way of doing it that can be useful is to have this map in a seperate xml file
<person>
<type> student </type>
<constructor> Student </type>
</person>
....
You can then read this xml file in to memory and use reflection to get back your constructor. For the given type. Given that you are using C++ however this will not be that simple as C++ does not have reflection as standard. You will have to look for an extension to provide you with reflection in C++.
But regardless, all these alternatives can not escape what you did in your original implementioan, ie: list the mapping from type to constructor and search the map.