design pattern for links - c++

I have a bunch of functors that take some data and build new ones when operator() is invoked.
class Functor {
void operator()() {
pt = BaseFactory(INPUT);
}
std::shared_ptr<BASE> pt;
};
The input data of the functors may contain some "local" data to the functor, some "global static" data, or the result of another functor.
In the first two cases, the functor knows where data is. The problem comes with the last case, since functors may be deleted, modified and re-run, leading to reallocation or deletion of the actual data.
I was thinking of developing a single interface of a Link, that basically acts as a proxy for the data. Something like:
template<typename T>
class Link {
T & get();
};
Maybe, provide specializations for Persistent and Builded types and, in the last case, also provide methods to query the memory state of the data (broken link) or to ask who is supposed to build it.
How this kind of problems is generally approached?
Bonus question :
how to correctly define operator< to allow the use of associative containers, without risking to lose data? For example to have:
class AnotherFunctor {
void operator()() {
for(auto & iter : map){
iter.second = BaseFactory(iter.first.get());
}
}
std::map<Link<INPUT>,std::shared_ptr<BASE>> map;
}

Related

Deciding to use at runtime a boost::static_vector or a std::vector

I have an application that I want to minimize dynamic allocation for efficiency.
I'm leaning forward using boost::static_vector in one of my classes for that reason. I'm not sure yet exactly how big my array will need to be to accommodate most situations but there are always exceptions...
Instead of discarding the input that would require more space than what my static_vector can store, I would like to fall back on std::vector to handle those exceptions.
A pattern that I commonly use in my classes design, is that I provide its input to the constructor to populate its container, then I provide a getter function that returns a const reference to the inner container.
The possibility that the class might use one or another container is causing a mental blind spot in me.
What would be the best way to offer access to the class elements?
I have come up with few ideas but none are truly satisfactory...
Make my class a container using the proxy/facade pattern
I'm too lazy for doing that and this is not practical if I want to apply this static_vector/vector solution everywhere...
Place the burden on the class user
ie.
void foo(HybridContainerObj &ojb) {
if (obj.IsUsingStaticVector()) {
const boost::static_vector<SomeElem> &vRef = obj.getStaticVec();
}
else {
const std::vector<SomeElem> &vRef = obj.getVec();
}
}
I doesn't feel right to me...
Modify boost::static_vector to do exactly what I have in mind
So far, this is my favorite solution...
Use some C++ magic that I am unaware of
Since both container classes do implement the same STL container concept, I wish that something along the lines would be possible:
const auto &vecRef = obj.getVec();
but AFAIK, this isn't possible... right?
So, I'm here to see what others think of that problem and if someone would have an elegant proposal to present the class used container elements to its users...
Greetings
boost::small_vector may be the combination you are looking for. From https://www.boost.org/doc/libs/1_60_0/doc/html/boost/container/small_vector.html:
small_vector is a vector-like container optimized for the case when it
contains few elements. It contains some preallocated elements
in-place, which can avoid the use of dynamic storage allocation when
the actual number of elements is below that preallocated threshold.
What you want is an "abstraction" over both std::vector and boost::static_vector, depending on what operations you want to do on the abstraction, you have different possibilities:
If you want const-access to the container, you can simply use a class that would wrap a raw array since both std::vector and boost::static_vector use a raw array internally. Fortunately for you, C++20 already has such class: std::span (if you don't have C++20, you can use the one from the GSL). This is the preferred option since it is probably completely transparent in term of performance and the interface of std::span is close to the read-only operations of std::vector or boost::static_vector.
If you want more operations (e.g. being able to push_back, etc.), you'd need a proper abstraction similar to what std::function does for functor objects, which requires a lot more work:
namespace details {
template <class T>
struct container_wrapper {
// All the operations you need.
virtual void push_back(T const& t) = 0;
};
template <class T>
class vector_wrapper: public container_wrapper<T> {
std::vector<T> *m_Vec;
public:
vector_wrapper(std::vector<T> &vec) : m_Vec{&vec} { }
void push_back(T const& t) override {
m_Vec->push_back(t);
}
};
template <class T>
struct static_vector_wrapper: public container_wrapper<T> {
boost::static_vector<T> *m_Vec;
public:
vector_wrapper(boost::static_vector<T> &vec) : m_Vec{&vec} { }
void push_back(T const& t) override {
m_Vec->push_back(t);
}
};
}
template <class T>
class my_container {
std::unique_ptr<details::container_wrapper> m_Wrapper;
public:
my_container(std::vector<T> &vec) :
m_Wrapper(std::make_unique<details::vector_wrapper<T>>(vec)) { }
my_container(boost::static_vector<T> &vec) :
m_Wrapper(std::make_unique<details::static_vector_wrapper<T>>(vec)) { }
};

Type erasure: Retrieving value - type check at compile time

I have a limited set of very different types, from which I want to store instances in a single collection, specifically a map. To this end, I use the type erasure idiom, ie. I have a non-templated base class from which the templated, type specific class inherits:
struct concept
{
virtual std::unique_ptr<concept> copy() = 0; // example member function
};
template <typename T>
struct model : concept
{
T value;
std::unique_ptr<concept> copy() override { ... }
}
I then store unique_ptrs to concept in my map. To retrieve the value, I have a templated function which does a dynamic cast to the specified type.
template <typename T>
void get(concept& c, T& out) {
auto model = dynamic_cast<model<T>>(&c);
if (model == nullptr) throw "error, wrong type";
out = model->value;
}
What I don't like about this solution is, that specifying a wrong T is only detected at runtime. I'd really really like this to be done at compile time.
My options are as I see the following, but I don't think they can help here:
Using ad hoc polymorphism by specifying free functions with each type as an overload, or a template function, but I do not know where to store the result.
Using CRTP won't work, because then the base class would need to be templated.
Conceptually I would need a virtual function which takes an instance of a class where the result will be stored. However since my types are fundamentally different, this class would need to be templated, which does not work with virtual.
Anyways, I'm not even sure if this is logically possible, but I would be very glad if there was a way to do this.
For a limited set of types, your best option is variant. You can operate on a variant most easily by specifying what action you would take for every single variant, and then it can operate on a variant correctly. Something along these lines:
std::unordered_map<std::string, std::variant<Foo, Bar>> m;
m["a_foo"] = Foo{};
m["a_bar"] = Bar{};
for (auto& e : m) {
std::visit(overloaded([] (Foo&) { std::cerr << "a foo\n"; }
[] (Bar&) { std::cerr << "a bar\n"; },
e.second);
}
std::variant is c++17 but is often available in the experimental namespace beforehand, you can also use the version from boost. See here for the definition of overloaded: http://en.cppreference.com/w/cpp/utility/variant/visit (just a small utility the standard library unfortunately doesn't provide).
Of course, if you are expecting that a certain key maps to a particular type, and want to throw an error if it doesn't, well, there is no way to handle that at compile time still. But this does let you write visitors that do the thing you want for each type in the variant, similar to a virtual in a sense but without needing to actually have a common interface or base class.
You cannot do compile-time type checking for an erased type. That goes against the whole point of type erasure in the first place.
However, you can get an equivalent level of safety by providing an invariant guarantee that the erased type will match the expected type.
Obviously, wether that's feasible or not depends on your design at a higher level.
Here's an example:
class concept {
public:
virtual ~concept() {}
};
template<typename T>
struct model : public concept {
T value;
};
class Holder {
public:
template<typename T>
void addModel() {
map.emplace(std::type_index(typeid(T)), std::make_unique<model<T><());
}
template<typename T>
T getValue() {
auto found = types.find(std::type_index(typeid(T)));
if(found == types.end()) {
throw std::runtime_error("type not found");
}
// no need to dynamic cast here. The invariant is covering us.
return static_cast<model<T>*>(found->second.get())->value;
}
private:
// invariant: map[type] is always a model<type>
std::map<std::type_index, std::unique_ptr<concept>> types;
};
The strong encapsulation here provides a level of safety almost equivalent to a compile-time check, since map insertions are aggressively protected to maintain the invariant.
Again, this might not work with your design, but it's a way of handling that situation.
Your runtime check occurs at the point where you exit type erasure.
If you want to compile time check the operation, move it within the type erased boundaries, or export enough information to type erase later.
So enumerate the types, like std variant. Or enumerate the algorithms, like you did copy. You can even mix it, like a variant of various type erased sub-algorithms for the various kinds of type stored.
This does not support any algorithm on any type polymorphism; one of the two must be enumerated for things to resolve at compile time and not have a runtime check.

Polymorphic converting iterator

Consider the following (simplified) scenario:
class edgeOne {
private:
...
public:
int startNode();
int endNode();
};
class containerOne {
private:
std::vector<edgeOne> _edges;
public:
std::vector<edgeOne>::const_iterator edgesBegin(){
return _edges.begin();
};
std::vector<edgeOne>::const_iterator edgesEnd(){
return _edges.end();
};
};
class edgeTwo {
private:
...
public:
int startNode();
int endNode();
};
class containerTwo {
private:
std::vector<edgeTwo> _edges;
public:
std::vector<edgeTwo>::const_iterator edgesBegin(){
return _edges.begin();
};
std::vector<edgeTwo>::const_iterator edgesEnd(){
return _edges.end();
};
};
I.e., I have two mostly identical edge types and two mostly identical container types. I can iterate over each kind individually. So far, so fine.
But now my use case is the following: Based on some criteria, I get either a containerOne or a containerTwo object. I need to iterate over the edges. But because the types are different, I cannot easily do so without code duplication.
So my idea is the following: I want to have an iterator with the following properties:
- Regarding its traversal behavior, it behaves either like a std::vector<edgeOne>::const_iterator or a std::vector<edgeTwo>::const_iterator, depending on how it was initialized.
- Instead of returning a const edgeOne & or const edgeTwo &, operator* should return a std::pair<int,int>, i.e., apply a conversion.
I found the Boost.Iterator Library, in particular:
iterator_facade, which helps to build a standard-conforming iterator and
transform_iterator, which could be used to transform edgeOne and edgeTwo to std::pair<int,int>,
but I am not completely sure how the complete solution should look like. If I build nearly the entire iterator myself, is there any benefit to use transform_iterator, or will it just make the solution more heavy-weight?
I guess the iterator only needs to store the following data:
A flag (bool would be sufficient for the moment, but probably an enum value is easier to extend if necessary) indicating whether the value type is edgeOne or edgeTwo.
A union with entries for both iterator types (where only the one that matches the flag will ever be accessed).
Anything else can be computed on-the-fly.
I wonder if there is an existing solution for this polymorphic behavior, i.e. an iterator implementation combining two (or more) underlying iterator implementation with the same value type. If such a thing exists, I could use it to just combine two transform_iterators.
Dispatching (i.e., deciding whether a containerOne or a containerTwo object needs to be accessed) could easily be done by a freestanding function ...
Any thoughts or suggestions regarding this issue?
How about making your edgeOne & edgeTwo polymorphic ? and using pointers in containers ?
class edge
class edgeOne : public edge
class edgeTwo : public edge
std::vector<edge*>
Based on some criteria, I get either a containerOne or a containerTwo object. I need to iterate over the edges. But because the types are different, I cannot easily do so without code duplication.
By "code duplication", do you mean source code or object code? Is there some reason to go past a simple template? If you're concerned about the two template instantiations constituting "code duplicaton" you can move most of the processing to an out-of-line non-templated do_whatever_with(int, int) support function....
template <typename Container>
void iterator_and_process_edges(const Container& c)
{
for (auto i = c.edgesBegin(); i != c.edgesEnd(); ++i)
do_whatever_with(i->startNode(), i->endNode());
}
if (criteria)
iterate_and_process_edges(getContainerOne());
else
iterate_and_process_edges(getContainerTwo());
My original aim was to hide the dispatching functionality from the code that just needs to access the start and end node. The dispatching is generic, whereas what happens inside the loop is not, so IMO this is a good reason to separate both.
Not sure I follow you there, but I'm trying. So, "code that just needs to access the start and end node". It's not clear whether by access you mean to get startNode and endNode for a container element, or to use those values. I'd already factored out a do_whatever_with function that used them, so by elimination your request appears to want to isolate the code extracting the nodes from an Edge - done below in a functor:
template <typename Edge>
struct Processor
{
void operator()(Edge& edge) const
{
do_whatever_with(edge.startNode(), edge.endNode());
}
};
That functor can then be applied to each node in the Container:
template <typename Container, class Processor>
void visit(const Container& c, const Processor& processor)
{
for (auto i = c.edgesBegin(); i != c.edgesEnd(); ++i)
processor(*i);
}
"hide the dispatching functionality from the code that just needs to access the start and end node" - seems to me there are various levels of dispatching - on the basis of criteria, then on the basis of iteration (every layer of function call is a "dispatch" in one sense) but again by elimination I assume it's the isolation of the iteration as above that you're after.
if (criteria)
visit(getContainerOne(), Process<EdgeOne>());
else
visit(getContainerTwo(), Process<EdgeTwo>());
The dispatching is generic, whereas what happens inside the loop is not, so IMO this is a good reason to separate both.
Can't say I agree with you, but then it depends whether you can see any maintenance issue with my first approach (looks dirt simple to me - a layer less than this latest incarnation and considerably less fiddly), or some potential for reuse. The visit implementation above is intended to be reusable, but reusing a single for-loop (that would simplify further if you have C++11) isn't useful IMHO.
Are you more comfortable with this modularisation, or am I misunderstanding your needs entirely somehow?
template<typename T1, typename T2>
boost::variant<T1*, T2*> get_nth( boost::variant< std::vector<T1>::iterator, std::vector<T2>::iterator > begin, std::size_t n ) {
// get either a T1 or a T2 from whichever vector you actually have a pointer to
}
// implement this using boost::iterator utilities, I think fascade might be the right one
// This takes a function that takes an index, and returns the nth element. It compares for
// equality based on index, and moves position based on index:
template<typename Lambda>
struct generator_iterator {
std::size_t index;
Lambda f;
};
template<typename Lambda>
generator_iterator< typename std::decay<Lambda>::type > make_generator_iterator( Lambda&&, std::size_t index=0 );
boost::variant< it1, it2 > begin; // set this to either one of the begins
auto double_begin = make_generator_iterator( [begin](std::size_t n){return get_nth( begin, n );} );
auto double_end = double_begin + number_of_elements; // where number_of_elements is how big the container we are type-erasing
Now we have an iterator that can iterate over one, or the other, and returns a boost::variant<T1*, T2*>.
We can then write a helper function that uses a visitor to extract the two fields you want from the returned variant, and treat it like an ADT. If you dislike ADTs, you can instead write up a class that wraps the variant and provides methods, or even change the get_nth to be less generic and instead return a struct with your data already produced.
There is going to be the equivalent of a branch on each access, but there is no virtual function overhead in this plan. It does currently requires an auto typed variable, but you can write an explicit functor to replace the lambda [begin](std::size_t n){return get_nth( begin, n );} and even that issue goes away.
Easier solutions:
Write a for_each function that iterates over each of the containers, and passes in the processed data to the passed in function.
struct simple_data { int x,y; };
std::function<std::function<void(simple_data)>> for_each() const {
auto begin = _edges.begin();
auto end = _edges.end();
return [begin,end](std::function<void(simple_data)> f) {
for(auto it = begin; it != end; ++it) {
simple_data d;
d.x = it->getX();
d.y = it->getY();
f(d);
}
};
};
and similar in the other. We now can iterate over the contents without caring about the details by calling foo->foreach()( [&](simple_data d) { /*code*/ } );, and because I stuffed the foreach into a std::function return value instead of doing it directly, we can pass the concept of looping around to another function.
As mentioned in comments, other solutions can include using boost's type-erased iterator wrappers, or writing a python-style generator mutable generator that returns either a simple_data. You could also directly use the boost iterator-creation functions to create an iterator over boost::variant<T1, T2>.

Using pointers, references, handles to generic datatypes, as generic and flexible as possible

In my application I have lots of different data types, e.g. Car, Bicycle, Person, ... (they're actually other data types, but this is just for the example).
Since I also have quite some 'generic' code in my application, and the application was originally written in C, pointers to Car, Bicycle, Person, ... are often passed as void-pointers to these generic modules, together with an identification of the type, like this:
Car myCar;
ShowNiceDialog ((void *)&myCar, DATATYPE_CAR);
The 'ShowNiceDialog' method now uses meta-information (functions that map DATATYPE_CAR to interfaces to get the actual data out of Car) to get information of the car, based on the given data type. That way, the generic logic only has to be written once, and not every time again for every new data type.
Of course, in C++ you could make this much easier by using a common root class, like this
class RootClass
{
public:
string getName() const = 0;
};
class Car : public RootClass
{
...
};
void ShowNiceDialog (RootClass *root);
The problem is that in some cases, we don't want to store the data type in a class, but in a totally different format to save memory.
In some cases we have hundreds of millions of instances that we need to manage in the application, and we don't want to make a full class for every instance.
Suppose we have a data type with 2 characteristics:
A quantity (double, 8 bytes)
A boolean (1 byte)
Although we only need 9 bytes to store this information, putting it in a class means that we need at least 16 bytes (because of the padding), and with the v-pointer we possibly even need 24 bytes.
For hundreds of millions of instances, every byte counts (I have a 64-bit variant of the application and in some cases it needs 6 GB of memory).
The void-pointer approach has the advantage that we can almost encode anything in a void-pointer and decide how to use it if we want information from it (use it as a real pointer, as an index, ...), but at the cost of type-safety.
Templated solutions don't help since the generic logic forms quite a big part of the application, and we don't want to templatize all this. Additionally, the data model can be extended at run time, which also means that templates won't help.
Are there better (and type-safer) ways to handle this than a void-pointer?
Any references to frameworks, whitepapers, research material regarding this?
If you don't want a full class, you should read up on FlyWeight pattern. It's designed to save up memory.
EDIT: sorry, lunch-time pause ;)
The typical FlyWeight approach is to separate properties that are common to a great number of objects from properties that are typical of a given instance.
Generally, it means:
struct Light
{
kind_type mKind;
specific1 m1;
specific2 m2;
};
The kind_type is often a pointer, however it is not necessary. In your case it would be a real waste because the pointer itself would be 4 times as big as the "useful" information.
Here I think we could exploit padding to store the id. After all, as you said it's going to be expanded to 16 bits even though we only use 9 of them, so let's not waste the other 7!
struct Object
{
double quantity;
bool flag;
unsigned char const id;
};
Note that the order of elements is important:
0x00 0x01 0x02 0x03
[ ][ ][ ][ ]
quantity flag id
0x00 0x01 0x02 0x03
[ ][ ][ ][ ]
id flag quantity
0x00 0x02 0x04
[ ][ ][ ][ ][ ][ ]
id -- quantity flag --
I don't understand the "extended at runtime" bit. Seems scary. Is this some sort of self-modifying code ?
Template allow to create a very interesting form of FlyWeight: Boost.Variant.
typedef boost::variant<Car,Dog,Cycle, ...> types_t;
The variant can hold any of the types cited here. It can be manipulated by "normal" functions:
void doSomething(types_t const& t);
Can be stored in containers:
typedef std::vector<types_t> vector_t;
And finally, the way to operate over it:
struct DoSomething: boost::static_visitor<>
{
void operator()(Dog const& dog) const;
void operator()(Car const& car) const;
void operator()(Cycle const& cycle) const;
void operator()(GenericVehicle const& vehicle) const;
template <class T>
void operator()(T const&) {}
};
It's very interesting to note the behavior here. Normal function overload resolution occurs, therefore:
If you have a Car or a Cycle you'll use those, every other child of GenericVehicle will us the 4th version
It's possible to specify a template version as a catch them all, and specify it appropriately.
I shall note that non-template methods can perfectly be defined in a .cpp file.
In order to apply this visitor, you use the boost::apply_visitor method:
types_t t;
boost::apply_visitor(DoSomething(), t);
// or
boost::apply_visitor(DoSomething())(t);
The second way seems odd, but it means you can use it in a most interesting fashion, as predicate:
vector_t vec = /**/;
std::foreach(vec.begin(), vec.end(), boost::apply_visitor(DoSomething()));
Read up on variant, it's most interesting.
Compile time check: you missed one operator() ? the compiler throws up
No necessity of RTTI: no virtual pointer, no dynamic type --> as fast as using a union, but with increased safety
You can of course segment your code, by defining multiple variants. If some sections of the code only deal with 4/5 types, then use a specific variant for it :)
In this case, it sounds like you should simply use overloading. For example:
#ifdef __cplusplus // Only enable this awesome thing for C++:
# define PROVIDE_OVERLOAD(CLASS,TYPE) \
inline void ShowNiceDialog(const CLASS& obj){ \
ShowNiceDialog(static_cast<void*>(&obj),TYPE); \
}
PROVIDE_OVERLOAD(Car,DATATYPE_CAR)
PROVIDE_OVERLOAD(Bicycle,DATATYPE_BICYCLE)
// ...
#undef PROVIDE_OVERLOAD // undefine it so that we don't pollute with macros
#endif // end C++ only
If you create overloads for your various types, then you will be able to invoke ShowNiceDialog in a simple and type safe manner, but you will still be able to leverage your optimized C variant of it.
With the code above, you could, in C++, write something like the following:
Car c;
// ...
ShowNiceDialog(c);
If you changed the type of c, then it would still use the appropriate overload (or give an error if there was no overload). It doesn't prevent one from using the existing type-unsafe C variant, but since the typesafe version is easier to invoke, I would expect that other developers would prefer it, anyway.
Edit
I should add that the above answers the question of how to make the API typesafe, not about how to make the implementation typesafe. This will help those using your system to avoid unsafe invocations. Also note that these wrappers provide a typesafe means for using types known already at compile-time... for dynamic types, it really would be necessary to use the unsafe versions. However, another possibility is that you could provide a wrapper class like the following:
class DynamicObject
{
public:
DynamicObject(void* data, int id) : _datatype_id(id), _datatype_data(data) {}
// ...
void showNiceDialog()const{ ShowNiceDialog(_datatype_data,_datatype_id); }
// ...
private:
int _datatype_id;
void* _datatype_data;
};
For those dynamic types, you would still not have much safety when it comes to constructing the object, but once the object were constructed, you would have a much safer mechanism. It would be reasonable to combine this with a typesafe factory so that users of your API would never actually construct the DynamicObject class themselves, and so would not need to invoke the unsafe constructor.
It's perfectly possible to change the packing of a class in, say, Visual Studio- you can use __declspec(align(x)) or #pragma pack(x) and there's an option in the property pages.
I would suggest that the solution is to store your classes in, say, vectors of each data member individually, then each class will hold just a reference to the master class and an index into these vectors. If the master class were to be a singleton, then this could be improved further.
class VehicleBase {
public:
virtual std::string GetCarOwnerFirstName() = 0;
virtual ~VehicleBase();
};
class Car : public VehicleBase {
int index;
public:
std::string GetCarOwnerFirstName() { return GetSingleton().carownerfirstnames[index]; }
};
Of course, this leaves some implementation details to be desired, such as the memory management of Car's data members. However, Car itself is trivial and can be created/destroyed at any time, and the vectors in GetSingleton will pack data members quite efficiently.
I would use traits
template <class T>
struct DataTypeTraits
{
};
template <>
struct DataTypeTraits<Car>
{
// put things that describe Car here
// Example: Give the type a name
static std::string getTypeName()
{
return "Car";
}
};
template <>
struct DataTypeTraits<Bicycle>
{
// the same for bicycles
static std::string getTypeName()
{
return "Bicycle";
}
};
template <class T>
ShowNiceDialog(const T& t)
{
// Extract details of given object
std::string typeName(DataTypeTraits<T>::getTypeName());
// more stuff
}
This way you don't need to change ShowNiceDialog() whenever you add a new type you want to apply it to. All you need is a specialization of DataTypeTraits for the new type.

C++ Templated return

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.