Operar con objetos de plantilla

EXENCIÓN DE RESPONSABILIDAD I'm not allowed to use BOOST or any other library, only standard.

En mi clase Foo I've a template function foo, which takes 2 parameters: a puntero a objeto y pointer-to-this-object-member-function. foo function works with pointer of any class, as you can see. I do NOT know, what class will be passed to it. This function creates an instance of a template structure.

template <typename TypeName>
struct Bar
{
    void(TypeName::*action)();
    TypeName* objPtr;
};



template <typename TypeName> void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr )
{
    Bar <TypeName> bar;
    bar.action = action;
    bar.objPtr = objPtr;
};

My question is: how do I store objects of Bar, creado en foo, so I can iterate through them later and call the pointer-to-an-object-member-function Me gusta esto:

(BarStorage[i].objPtr->*BarStorage[i].action)();

preguntado el 28 de agosto de 12 a las 12:08

pointer-to-an-object-member-function es esencialmente un delegar. Maybe it will help you. -

You're not even allowed to use the standard library, which in C++11 has very good support for function objects and binding? -

You cannot store instances of Bar porque Bar is a class template, so you cannot make instances of it. -

Only standard is allowed, including C++11. -

So std::function y std::bind debería ser suficiente. -

1 Respuestas

Utilice las borrado tipo:

class BarBase {
    virtual void invoke() = 0;
};

template<typename TypeName>
class Bar final : public BarBase {
    void(TypeName::*action)();
    TypeName* objPtr;
    virtual void invoke() override { (objPtr->*action)(); }
};

class Foo {
    std::vector<std::unique_ptr<BarBase>> myBars;
/* ... */
};

template <typename TypeName>
void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr)
{
    auto bar = new Bar<TypeName>();
    bar->action = action;
    bar->objPtr = objPtr;
    myBars.emplace_back(bar);
};

entonces simplemente llama myBars[x]->invoke();


To answer questions in comments.

Que pasa con override? Explicitly say that you override virtual function from a base class. This is not really necessary here, but is considered good practice. For more details see Artículo de Wikipedia.

Its a new feature from C++11, some compilers supported this feature in one way or another for a long time, but its been standardized only now. GCC should support this feature from version 4.7 - you have to use command line parameter -std=c++0x.

Que pasa con unique_ptr? It makes life easier. When you allocate new Bar<XXX>(), you must at some point say delete to free that memory. If you put the pointer in a resource managing object like unique_ptr, you no longer need to worry about deleting it. With vector<BarBase*> you would have to declare a destructor in Foo que hace algo como:

for each element in myBars
    delete element

Si utiliza vector<unique_ptr<BarBase>>, you don't need to worry about deleting anything. When vector is destroyed at end of Foo's life, it will destroy its elements - and unique_ptr deletes the memory it contains in its own destructor.

This is also C++11 feature - addition to standard library. You don't have to use it (but then make sure to delete everything at the end).

Que pasa con auto? Instead of repeating the same type twice (Bar<Type> * bar = new Bar<Type>();), just use it once and let the compiler deduce the correct type of the variable based on the type of the initializer. It behaves exactly the same, its just less typing and looks better :)

Also C++11 feature, supported in GCC since v4.4.

¿Por qué myBars[x]->invoke() hace lo correcto? Porque invoke is declared virtual in BarBase. This means the method executed is chosen based on the dynamic type (the real type during execution) of myBars[x], not static type. For in-depth explanation, see wiki. There is a minor run-time overhead with this mechanism, but it can't be helped when dealing with dynamic types.

Respondido 28 ago 12, 16:08

man, this is an INCREÍBLE idea. Gonna try this out! Thanks much. - Kolyunya

@Fiktik, may I ask you some questions concerning your code, please? My compiler g++ doesn't know this syntax with override key-word. Is it a new standard or what? I just type virtual void invoke() { (objPtr->*action)(); }. Second: why do you use unique_ptr, No sólo vector<BarBase*> myBars;. Third, what is auto? Again some new feature in new standard? I just type Bar<TypeName>* bar = new Bar <TypeName> ( ); - Kolyunya

And the main question: why myBars[x]->invoke(); calls overridden function and not the base function? myBars almacena punteros para BarBases, so why not the base function is called? - Kolyunya

@Kolyunya I've added the explanation to the answer. - fiktik

@Fiktik, thanks for help and maybe you will find a minute to look at the continuation of the problem here? stackoverflow.com/questions/12178280/… - Kolyunya

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.