Topic: Pointers to member functions


Author: "Default User"<defaultuserbr@yahoo.com>
Date: Wed, 24 Aug 2011 17:38:11 -0700 (PDT)
Raw View
This is a follow-up to a discussion from over in CLC++.

Background. I'm working on a number of modules that all derive from a common
base class. Part of the design that I came up with maps integer operation
codes to pointers to member functions. After I did few, I noticed that I had
identical functions (represented in the example below by "write" and
"list"). So my thoughts were to try to push them down to the base class.
This all seemed to "work", meaning that it built without issue and gave the
results I was looking for.

The fine folks over on the other group have pretty much convinced me that
it's undefined behavior. I guess the big problem is that there isn't a
round-trip on the function pointers, they're still a pointer to baseclass
member function when called.

I just wanted to run this past here to double-check that, and to see if
there was perhaps something that could be done to tweek what I have and get
a similar structure that was legal.


Brian

// This is example code only that gives the flavor of what I'm doing.
// Please accept on faith that I really do need to do the mapping described.

#include<iostream>
#include<map>
#define CALL_HANDLER(object,ptrToMember)((object).*(ptrToMember))

class tbase
{
public:
    typedef int (tbase::*HandlerPtr)(int);
    void write(int data, int code)
    {
       std::map<int, HandlerPtr>::iterator it;
       it = handlers.find(code);
       if (it != handlers.end())
       {
          // Found, call the function pointer
          CALL_HANDLER(*this, it->second)(data);
       }
       else // unhandled code
       {
          // error handling
       }
    }
    void list()
    {
       std::map<int, HandlerPtr>::iterator it = handlers.begin();

       std::cout<<  "Supported Op codes:\n";
       while (it != handlers.end())
       {
          std::cout<<  it->first<<  "\n";
          it++;
       }
    }
protected:
    tbase()
    {
    }
    virtual ~tbase()
    {
    }
    std::map<int, HandlerPtr>  handlers;
};

class test : public tbase
{
public:
    test()
    {
       handlers[0] = static_cast<HandlerPtr>(&test::H0);
       handlers[4] = static_cast<HandlerPtr>(&test::H4);
    }
    virtual ~test()
    {
    }
    virtual int H0(int data)
    {
       std::cout<<  "test::H0: "<<  data<<  "\n";
       return data;
    }
    int H4(int data)
    {
       std::cout<<  "test::H4: "<<  data<<  "\n";
       return data;
    }

};

int main()
{
    test t;
    t.list();
    t.write(123, 0);
    t.write(456, 4);
    return 0;
}




--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: =?ISO-8859-15?Q?Daniel_Kr=FCgler?=<daniel.kruegler@googlemail.com>
Date: Thu, 25 Aug 2011 20:51:51 CST
Raw View
Am 25.08.2011 02:38, schrieb Default User:
>  Background. I'm working on a number of modules that all derive from a common
>  base class. Part of the design that I came up with maps integer operation
>  codes to pointers to member functions. After I did few, I noticed that I had
>  identical functions (represented in the example below by "write" and
>  "list"). So my thoughts were to try to push them down to the base class.
>  This all seemed to "work", meaning that it built without issue and gave the
>  results I was looking for.
>
>  The fine folks over on the other group have pretty much convinced me that
>  it's undefined behavior. I guess the big problem is that there isn't a
>  round-trip on the function pointers, they're still a pointer to baseclass
>  member function when called.

It seems to me that the code is well-formed and well-defined. IMO the
meaning in regard to the pointer-to-member operations is fully described
by 5.2.9 [expr.static.cast] p9, 5.5 [expr.mptr.oper] p2+4+6 in the C++03
standard (Only little has been changed for C++11, and nothing which is
related to your example).

>  I just wanted to run this past here to double-check that, and to see if
>  there was perhaps something that could be done to tweek what I have and get
>  a similar structure that was legal.
>
>
>  Brian
>
>  // This is example code only that gives the flavor of what I'm doing.
>  // Please accept on faith that I really do need to do the mapping described.
>
>  #include<iostream>
>  #include<map>
>  #define CALL_HANDLER(object,ptrToMember)((object).*(ptrToMember))
>
>  class tbase
>  {
>  public:
>       typedef int (tbase::*HandlerPtr)(int);
>       void write(int data, int code)
>       {
>          std::map<int, HandlerPtr>::iterator it;
>          it = handlers.find(code);
>          if (it != handlers.end())
>          {
>             // Found, call the function pointer
>             CALL_HANDLER(*this, it->second)(data);
>          }
>          else // unhandled code
>          {
>             // error handling
>          }
>       }
>       void list()
>       {
>          std::map<int, HandlerPtr>::iterator it = handlers.begin();
>
>          std::cout<<    "Supported Op codes:\n";
>          while (it != handlers.end())
>          {
>             std::cout<<    it->first<<    "\n";
>             it++;
>          }
>       }
>  protected:
>       tbase()
>       {
>       }
>       virtual ~tbase()
>       {
>       }
>       std::map<int, HandlerPtr>    handlers;
>  };
>
>  class test : public tbase
>  {
>  public:
>       test()
>       {
>          handlers[0] = static_cast<HandlerPtr>(&test::H0);
>          handlers[4] = static_cast<HandlerPtr>(&test::H4);
>       }
>       virtual ~test()
>       {
>       }
>       virtual int H0(int data)
>       {
>          std::cout<<    "test::H0:"<<    data<<    "\n";
>          return data;
>       }
>       int H4(int data)
>       {
>          std::cout<<    "test::H4:"<<    data<<    "\n";
>          return data;
>       }
>
>  };
>
>  int main()
>  {
>       test t;
>       t.list();
>       t.write(123, 0);
>       t.write(456, 4);
>       return 0;
>  }

I could have overlooked something, but what I see looks well-formed and
well-defined: In particular [expr.static.cast] p9 supports the
conversion and the evaluation is well-defined, because the dynamic type
does indeed contain the referred to member. Also, there is nothing in
the standard that requires that the functions need to be virtual, to
make this well-defined.

HTH&  Greetings from Bremen,

- Daniel Kr   gler



--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Default User" <defaultuserbr@yahoo.com>
Date: Fri, 26 Aug 2011 11:19:07 -0700 (PDT)
Raw View
"Daniel Kr=FCgler" <daniel.kruegler@googlemail.com> wrote in message
news:j365vr$4o8$1@dont-email.me...
>
> Am 25.08.2011 02:38, schrieb Default User:
>>  The fine folks over on the other group have pretty much convinced me
>> that
>>  it's undefined behavior.

> It seems to me that the code is well-formed and well-defined. IMO the
> meaning in regard to the pointer-to-member operations is fully described
> by 5.2.9 [expr.static.cast] p9, 5.5 [expr.mptr.oper] p2+4+6 in the C++03
> standard (Only little has been changed for C++11, and nothing which is
> related to your example).

In the interim between the original post and yours, opinion on CLC++ shifte=
d
to your conclusion. Thanks for the second look. I feel confident going
forward with this solution now. It will save a good deal of duplicate code
in the subclasses.



Brian



--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]