4

I've a class

class BarBase {

};

and a derived template class, which stores a pointer to a member function and a pointer to an object of the same class

template<typename TypeName> class Bar: public BarBase
{
    void ( TypeName::*action ) ( void );
    TypeName* object;
};

I create instances of Bar and store pointers to them in the vector of another class Foo

class Foo {
    private:
        vector<BarBase*> myBars;
    ...
};

Now to the question. Foo has a template function

template <typename TypeName>
void Foo::foo( TypeName* object , void ( TypeName::*action ) ( void ) )

In this function how do I find in myBars elements with fields object and action equal to parameters of this function? As you can see, I can not directly access the fields like this->myBars[i]->action since these fields are not (and can not be) members of BarBase.

EDIT I do can compare object. I add a virtual size_t getObject (){}; to BarBase and override it in Bar like virtual size_t getObject (){ return (size_t)this->object; };. Then I compare two size_t , but I do not know, how to convert action to a number...

Kolyunya
  • 5,973
  • 7
  • 46
  • 81
  • 1
    There is no correct and simple solution for this problem. You can use dynamic_cast in loop and check, that dynamic_cast returns not null value – ForEveR Aug 29 '12 at 12:47
  • @ForEveR added an update to the question. – Kolyunya Aug 29 '12 at 12:52
  • You can cast function pointer to void* using reinterpret_cast, but it's not correct way. – ForEveR Aug 29 '12 at 13:04
  • @ForEveR: A pointer to member function is not a function pointer. – aschepler Aug 29 '12 at 13:12
  • @aschepler yeah, sorry, but you can convert pointer to member function to void* using reinterpret_cast (in gcc without -pedantic key). – ForEveR Aug 29 '12 at 13:14
  • 2
    @ForEveR that may result in undefined behavior , void ptr and member fn pointer are of diff sizes – Mr.Anubis Aug 29 '12 at 13:17
  • actually in your `Foo::foo()`, are you going to call `(object->*action)()` and do not need pointer `object` itself? If so, there might be a way to accomplish what you want. – user2k5 Aug 29 '12 at 13:28
  • @ForEveR: You **cannot** convert a pointer-to-member to a `void*` in C++. They might not even have the same size in memory. – David Rodríguez - dribeas Aug 29 '12 at 14:00
  • @DavidRodríguez-dribeas yeah, yeah. it's my fault. – ForEveR Aug 29 '12 at 14:04
  • You're implement type-erasure. You might be interested in [available techniques](http://stackoverflow.com/questions/5450159/type-erasure-techniques), and in the [interface of `boost::function`](http://www.boost.org/doc/libs/1_51_0/doc/html/boost/functionN.html) (or similarly `std::function`). In particular note the `target_type` and `target` members, which offer a `typeid`-based solution (which is an alternative to a `dynamic_cast`-based solution). – Luc Danton Aug 29 '12 at 14:28

2 Answers2

2

The simplest solution is to make the base class polymorphic, and use dynamic_cast to determine whether it has the expected type:

class BarBase {
public:
    virtual ~BarBase() {}  // virtual function required for polymorphism
};

Bar<TypeName>* bar = dynamic_cast<Bar<TypeName>*>(myBars[i]);
if (bar && bar->object == object && bar->action == action) {
    // it's a match
}

This does add some overhead to support RTTI; off the top of my head, I can't think of any well-defined way to do this that doesn't add overhead.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 2
    Note this will never consider a `Bar` and `Bar` the same, even if they contain pointers to the same most-derived object and the same member. – aschepler Aug 29 '12 at 13:13
  • @MikeSeymour, thanks for an answer, nice solution. May I ask you, why is virtual destructor required and how this conception works? Thanks! – Kolyunya Aug 29 '12 at 13:58
  • @Kolyunya: `dynamic_cast` works by using run-time type information (RTTI) to ask the object whether its dynamic type is `Bar`. This is only possible if the type is *polymorphic*, which means it has at least one virtual function. If you don't need any virtual functions, then a simple way to achieve this is to make the destructor virtual. – Mike Seymour Aug 29 '12 at 14:13
1

You can use something like this, if you don't want use Mike variant (i prefer his variant).

class BarBase 
{
public:
   virtual ~BarBase() { }
   virtual void* getObject() { return 0; }
   virtual const char* getFunctionName() { return 0; }
};

template<typename T>
class Bar : public BarBase
{
public:
   Bar(T* obj, void (T::*func) (void)):object(obj), action(func)
   {
   }
   virtual void* getObject() { return object; }
   virtual const char* getFunctionName() { return typeid(action).name(); }
   T* object;
   void (T::*action)(void);
};

http://liveworkspace.org/code/d79e33d4597ee209645026b2100330f3

EDIT.

Sorry. It's not solution of problem, since typeid(&S::action).name() may be equal to typeid(&S::other_action).name().

Also, you can use dynamic_cast or static_cast not for all objects in vector.

class BarBase 
{
public:
   virtual ~BarBase() { }
   virtual void* getObject() const { return 0; }
};

template<typename T>
class Bar : public BarBase
{
public:
   Bar(T* obj, void (T::*func) (void)):object(obj), action(func)
   {
   }
   virtual void* getObject() const { return object; }
   T* object;
   void (T::*action)(void);
};

for (auto pos = objects.begin(); pos != objects.end(); ++pos)
{
      if ((*pos)->getObject() == &p)
      {
         auto bar = static_cast<Bar<S>*>(*pos);
         if (bar->action == act)
         {
            // right object founded.
         }
      }
   }

http://liveworkspace.org/code/87473a94411997914906c22ef0c31ace

ForEveR
  • 55,233
  • 2
  • 119
  • 133