access non static member function

I am trying to implement a very simple dictionary, one that will store a pointer to a member function, along with a key to find and return or call that pointer.

Here is my code:

Class(es) header file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
typedef void (*func_t());
class D1;

/* D is a simplistic disctionary to store function pointers addressed by keys 
	 (some implentations not included here)												*/
class D  
{
public:
		D();
		~D();

		/* add member function pointer f 						*/
		void	add_func(const char* key, func_t* f);

		/* return member function pointer referenced by "key" 	*/
		func_t*	get_func(const char* key);

		/*  get member function pointer referenced by "key"
				and execute it									*/
		void	dofunc(const char* key);


};

class D1 : public D
{
public:
	D1();
	~D1();

	// would like to actually have these "virtual"

	void	f1(){};
	void	f2(){};
	void	f3(){};
	void	f4(){};

};


The class(es) implementation(s):
[code]
#include "D.h"

D::D(){};
D::~D(){};

void
D::add_func(const char* key, func_t* f){};

func_t*
D::get_func(const char* key){
    func_t *f;

    // search for key, and set f to the value

    return f;
    };
void
D::dofunc(const char* key){
    func_t *f = get_func(key);
    f();
}

D1::D1(){
    add_func("1",f1);
    add_func("2",f2);
    add_func("3",f3);
    add_func("4",f4);
};
D1::~D1(){};


And the main code:

1
2
3
4
5
6
7
8
9
10
11
12
#include "D.h"

/* fetch and execute function D1::f1 */

int main()
{
    D1  x;
    
    x.dofunc("1");
} 



Here is what the compiler griped:
1
2
3
error: invalid use of non-static member function ‘void D1::f1()’
   30 |     add_func("1",f1);
      |                  ^~


I kinda understand that the address of a non-static function can't be determined at compile time. So my question becomes not "why", but "how". How do I make this design work? The brute force method would be to change the fetch function to something like this:

1
2
3
4
5
6
7
8

void do_brute(const char* key){
   if (strcmp(key, "key1") == 0)
      f1();
   else if ...
   else { /* handle error case */

};


But then every time I (or someone else) needed to add a new function, a new else if {} statement would need to be added to the do_brute function. That kind of defeats the purpose. Especially if this class was part of a shared library.

Any suggestions, advice, ...?

TIA

ken
PS: the preview didn't show any of the text of this message. Sorry if it isnt "pretty".


Last edited on
Which C++ language standard does your code obey?

And... why do you want to do this?
Last edited on
You seem to be looking for a pointer-to-member-function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

class Base
{
protected:
    int n;
public:
    Base(int n) : n(n) { }
    virtual ~Base() = default;
    virtual void show() const { std::cout << "Base: " << n << '\n'; }
};

class Derived: public Base
{
public:
    Derived(int n) : Base(n) { }
    void show() const override { std::cout << "Derived: " << n << '\n'; }
};

using func_t = void(Base::*)() const; // or typedef void(Base::*func_t)() const;

int main()
{
    func_t pf = &Base::show;

    Base *b = new Base(42);
    (b->*pf)();  // if b was not a pointer it would be (b.*pf)()

    Base *d = new Derived(99);
    (d->*pf)();

    delete b;
    delete d;
}

Note that C++17 has std::invoke which makes this easier.
And you could also use smart pointers instead of raw pointers.

1
2
3
4
5
6
7
8
9
10
int main()
{
    func_t pf = &Base::show;

    auto b = std::make_unique<Base>(42);  // include <memory>
    std::invoke(pf, b);                   // include <functional>

    auto d = std::make_unique<Derived>(99);
    std::invoke(pf, d);
}

Last edited on
1
2
[ken@Bugs ~]$ clang -dM -E -x c++  /dev/null | grep -F __cplusplus
#define __cplusplus 201402L 


Does "why" matter? Basically, the applications that will be using this class need to dynamically call a member function, but only knowing a key (const char*) specifying which one.New functions, with associated keys, could added later, probably by a derived class (such as D1). As I said, the base class will be implemented in a shared library (.so). And the brute force method is the only alternative I can think of.

If you know a better way to implement something like this, please let me know.

ken
Does "why" matter?

Approaching an esoteric problem with no context is a brilliant way to solve problems that don't need to be solved.

Consider
std::unordered_map<std::string, std::function<void(D1&)>>
Last edited on
@dutch:

This looks more like I need (dang! I fogot about ->*). But just a few clarifications for me:

I assume that 42 and 99 are the keys for each func_t, and each class is for one single funct_t. For me, each derived class would add 1 or more func_t's.

Also for me, the add/fetch/do_func members would be defined in the base class "D", and wouldn't need to be overridden. Each derived class would define there own "fX()" members, or even override "fX()" members in lower classes.

thus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

int main(...){
   D   d; 
   D1   d1;    // derived classes with own set of func_t's
   D2   d2;
  const char *key1 = "Key1";
  const char *key2 = "Key2";
   ...
  const char *keyN = "KeyN";

   d.add_func(key1, &D1::f1);   // this could be done in the constructor of D1.
   d.add_func(key2, &D1::f2);  // is "DX::" needed?
   d.add func(key3, &D2::f3);
   ...
   d.do_func(key1);   //   would do D1::f1
   d.do_func(key2);   //    would do D1::f2
   d.do_func(key3);    //   would do D2::f3
   ...
 
}


and in the code for D:
1
2
3
4
5

void D::do_func(const char* key){
   funct_t *pf = fectch(key);   // key could be for any func_t of any derived class
   pf->*();
}


This would be what I want: add to D's dictionary like container any key/funct_t from any derived class (using base class "add_func", then fetch a func_t - from any class - via the base "do_func".

Does this make sense? And work?

(as for using templates: I have a personal aversion for using them :-( )

thx (again).

ken

Here's some code but it doesn't do what you are asking for. I don't really understand what you want. Your best bet is to describe exactly what you want from the highest problem level (not an implementation level) so that someone can come up with a workable solution.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <map>

class D;
using func_t = void(D::*)();

class D {
    std::map<const char*,func_t> m;
public:
    void do_func(const char* key);
    void add_func(const char* key, func_t f);
    void f1() { std::cout << "f1\n"; }
    void f2() { std::cout << "f2\n"; }
};

void D::add_func(const char* key, func_t f) {
    m.insert(std::make_pair(key, f));
}

void D::do_func(const char* key) {
    auto it = m.find(key);
    if (it == m.end())
        std::cout << "key not found\n";
    else {
        auto pf = it->second;
        (this->*pf)();
    }
}

int main() {
    D d;

    d.add_func("key1", &D::f1);
    d.add_func("key2", &D::f2);

    d.do_func("key1");
    d.do_func("key2");
}

That's pretty much it. Only (small) difference is that I'm not using "std::map" for a dictionary. The base class "D" does that functionality. The derived classes implement the various functions that are stored and accessed by the base class.

As for the implementation: this shared lib is simply wrappers around a lib of C of calls. Some of the new C++ function implementations become a C++ class w/ (non-static) member funcs as callbacks. I guess the one missing part woud be:

1
2
3
4
5
6
7
8
9
10
/* info: is event info that generated the callback, would be specific to each function
   key: is the string associated with the event
   pthis: is a pointer to a base class ("D") instance that would find the 
   appropriate function via key, then call that function. */

using func_t = void(D::*)(void *);
void static D::main_cb(void *info, const char* key, void *pthis){
   func_t *pf = (funct_t *)pthis;
   (pf->*)(do_func(info));    
}


Typically, the static callback "main_cb" would call pf->fixed_func_t();. But the specific "fixed_func_t" is not known at compile time, and only known indirectly at run time via the "key". This replaces adding new static member callbacks for each new func_t, That doesn't seem very elegant to me.

Does that now make better sense? Do you think it will work?

thx again,

ken

Okay, I've narrowed down the problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

   class D;
   using func_t = void (D::*)(void*);

class D{
public: 
  ...
   void addfunc(const char* key, func_t f) {m_key=key;m_f = f;};
   funct_t getfunc(const char* key){return m_f;};
   void dofunc(const char* key, void* data){
   funct t=getfunc(const char* key){
      (this->*t)(v);
   };
};

protected:
   funct_t   m_f;
   const char* m_key;
}
class D1 : public D
{
   ...
   void f11(void* pd){};
}
#define FUNC_REF(class, func)   ????
int main()
{
   D1 d;
   func_t  f;

   d.addfunc("1", FUNC_REF(D1, f11));
   f = d.getfunc("1")

   /*  both equivalent */
   (x.*f)(v);
   d.dofunc("1");
}


I need to know how to define FUNC_REF where class is a derivative of D, and func is a member of that class, of type func_t. That's why (and I understand why):
1
2
     /* won't work. Compiler won't convert "D1" to "D" */
     func_t f = &D1::f11;


Is there a way around this?
The problem is about associating data (pointers) with type information only known at runtime. This association is always done with a multi-way branch. Since branching is a mildly important operation the computer offers a number of ways to do it.

This operation can be implemented as a million if statements, but since writing all the cases by hand isn't an attractive solution, the compiler can be made to do it while recording RTTI.

Consider:

Edit: this first snippet is wrong: see http://www.cplusplus.com/forum/general/275610/#msg1189873
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <cstdio>
#include <utility>
#include <memory>

template <typename T> using member_procedure = void(T::*)();

struct dictionary_entry_interface
{
  virtual ~dictionary_entry_interface() = default;
  virtual void call(void* implicit_object) const = 0;
};

template <typename T>
  class dictionary_entry_implementation
    : public dictionary_entry_interface
  {
    member_procedure<T> pmfn_;
  public:
    explicit dictionary_entry_implementation(member_procedure<T> pmfn)
      : pmfn_(std::move(pmfn))
    {}

    virtual void call(void* implicit_object) const override
    { 
      (static_cast<T*>(implicit_object)->*pmfn_)();
    }
  };

class dictionary_entry
{
  std::unique_ptr<dictionary_entry_interface const> impl_; 
public:
  dictionary_entry() = default;
  template <typename T> 
    explicit dictionary_entry(member_procedure<T> pmfn)
      : impl_(std::make_unique<dictionary_entry_implementation<T>>(pmfn))
    {}

  void operator()(void* implicit_object) const 
  {
    return impl_? impl_->call(implicit_object): throw 0;
  }
};


#include <cstdio>
#include <unordered_map>
#include <string>

struct d1     { void f() { std::puts("d1::f"); } };
struct d2     { void g() { std::puts("d2::g"); } };
struct d3: d1 { void h() { std::puts("d3::h"); } };

int main()
{
  std::unordered_map<std::string, dictionary_entry> m;
  m["d1::f"] = dictionary_entry{&d1::f};
  m["d3::h"] = dictionary_entry{&d3::h};

  d3 x;
  m["d1::f"](&x);
  m["d3::h"](&x);

  d1 y;
  // m["d3::h"](&y); // undefined behavior; pointer types are not checked
}


In the code you've presented so far, d1, d2, d3 each inherit from a base class. While there is no fundamental requirement that these types are related, it may be safer to inherit because it allows better static and runtime (with dynamic_cast) type-checking as follows, assuming the base class is polymorphic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <cstdio>
#include <utility>
#include <memory>

template <typename T> using member_procedure = void(T::*)();

template <typename Base>
  struct dictionary_entry_interface
  {
    virtual ~dictionary_entry_interface() = default;
    virtual void call(Base& implicit_object) const = 0;
  };

template <typename Base, typename T>
  class dictionary_entry_implementation
    : public dictionary_entry_interface<Base>
  {
    member_procedure<T> pmfn_;
  public:
    explicit dictionary_entry_implementation(member_procedure<T> pmfn)
      : pmfn_(std::move(pmfn))
    {}

    virtual void call(Base& implicit_object) const override
    { 
      (dynamic_cast<T&>(implicit_object).*pmfn_)();
    }
  };

template <typename Base>
  class dictionary_entry
  {
    std::unique_ptr<dictionary_entry_interface<Base> const> impl_; 
  public:
    dictionary_entry() = default;
    template <typename T> 
      explicit dictionary_entry(member_procedure<T> pmfn)
        : impl_(std::make_unique<dictionary_entry_implementation<Base, T>>(pmfn))
      {
        static_assert(std::is_convertible<T, Base>::value, 
          "Base is a accessible base class of T");
      }

    void operator()(Base& implicit_object) const 
    {
      return impl_? impl_->call(implicit_object): throw 0;
    }
  };

#include <cstdio>
#include <unordered_map>
#include <string>

struct base { virtual ~base() = default; };
struct d1: base { void f() { std::puts("d1::f"); } };
struct d2: base { void g() { std::puts("d2::g"); } };
struct d3: d1   { void h() { std::puts("d3::h"); } };

int main()
{
  std::unordered_map<std::string, dictionary_entry<base>> m;
  m["d1::f"] = dictionary_entry<base>{&d1::f};
  m["d3::h"] = dictionary_entry<base>{&d3::h};

  d3 x;
  m["d1::f"](x);
  m["d3::h"](x);

  try
  {
    d1 x;
    m["d3::h"](x);
  } catch(std::bad_cast const& e) { std::puts(e.what()); }
}

In this snippet, dictionary_entry<base> represents any member function pointer within the class hierarchy whose root class is base.

Last edited on
This may be a solution, albeit complex with STL. This might be okay, if it was "hidden" inside a library, so that all that the end user would need to implement (in derived DX class) would be a member function with the typedef signature of func_t (void f()), or something similar. Consider one more addition to the original problem at hand:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

class D  
{
public:
		D();
		~D();

		/* add member function pointer f 						*/
		void	add_func(const char* key, func_t* f);

		/* return member function pointer referenced by "key" 	*/
		func_t*	get_func(const char* key);

		/*  get member function pointer referenced by "key"
				and execute it									*/
		void	dofunc(const char* key);
private:   // added to the original post. this is essentially unseen/not needed by end user
   static callback(const char *key){dofunc(key);};  //note that this is defined only in the base D class

};
class D1 : public D {
    ...
    void f1();
}


In another third party library ("C" functions only), there would be this:

1
2
3
4
5
6
7
8

typedef (*cb)(const char* key)();

// key is the same reference value, and cbf would be explicitly D::callback. 
void addcallback(const char*key, cb cbf);  

void somefunction(){...; (cbf)("key");...};
}


This is a typical "C" callback scenario. Now for the end user:

1
2
3
4
5
6
7
8

...
   D1 d;

   d.addfunc("keyD1", &f1);  // this would call addcallback("keyD1", &D::callback), 
                                            //with f1 implicitly D1::f1.

....


The "C" code at some point would issue the callback to the static D::callback. When that calls dofunc(key), will it get the right class DX func_t function? That is the real problem I have.

I would be very cautious about using const char * as the type of your key.
void add_func(const char* key, func_t* f);
If the key being passed is a local variable, that variable can go out of scope leaving your key as a hanging pointer.
Consider:
1
2
3
4
void some_func ()
{  const char * localvar = "F1";
    add_func (localvar, f1);
} // localvar is now out of scope 


You have some alternatives:
1) Make your own copy of the key value.
2) Use std::string as your key type. std::string will make a copy of the key value.
3) Use smart pointers to manage pointer to the key.
4) Make localvar static.
Last edited on
That is a typical newbie "C" error. Usually found on question in finals exam. If the lib developer (me) would assume that "const" meant constant pointer (as opposed to constant characters), then he/she/it would deserve their fate. :-) (off topic)
Last edited on
The first (but not second) snippet I posted is totally wrong.

Pointer-to-member functions can't be converted to void* (or anything, really); their sizes may differ, often depending on characteristics of the class type. A typical maximum size for a pointer-to-member is 3*sizeof(void*), e.g., when the class type is incomplete.

You'll need to use a small buffer of char or similar to pass member function pointers, not void*.
Last edited on
dutch wrote:

using func_t = void(Base::*)() const;

What is this declaring? It looks like it's creating an alias for an anonymous function pointer but what's the meaning of Base::*? Does func_t belong to Base?

dutch wrote:

b->*pf

What's going on here? pf is a function pointer and dereferencing it gives you a function but what's the meaning of b->(a function)?
Okay all. I have been looking at the ideas that you have posted here, and spent time experimenting. And now I think I might have a working solution. I won't mark this thread solved just yet. I'll give you some time to see what you think.

Note 1) The code here is only to show a method to do what I need. The actual application is much more complicated to show everything here.
Note 2) As per above, I left out all of the dictionary functionality here, since it is not relevant to the solution.

So here's the code:
d.h (defines base class and possible derived classes)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#ifndef X_H
#define X_H

class D;
using func_t = void (D::*)(void*);

typedef struct 
{
	const char* key;
	D* pd;
	func_t f;
}d_info;

class D  
{
public:
		D();
		~D();

		void	add_func(const char* key ,func_t f);
		static	d_info	*get_info(const char*key);
		static void	stat_dofunc(const char* k, void* data);
protected:

};

class D1 : public D
{
public:
	D1();
	~D1();

	void	f11(void* v){};
	void	f12(void* v){};

};

class D2 : public D
{
public:
	D2();
	~D2();

	void	f21(void* v){};
	void	f22(void* v){};

};

#endif 


d.cpp (the class implentantions)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "D.h"

D::D(){};
D::~D(){};

void
D::add_func(const char* key func_t f){
    d_info *pdi = new d_info;
    pdi->f = f;
    pdi->key = key;
    pdi->pd = this;
     // insert pdi into dict. (not shown here)
};

d_info*
D::get_info(const char* key){
    d_info *pd; // = find info in dict. with key (not shown here)
    return pd;
}
void
D::stat_dofunc(const char* k, void* data)
{
    d_info *pdi = get_info(k);
    ((pdi->pd)->*(pdi->f))(data);
};
/* "add_func" calls could be done somewhere else
    in code. this is just for convenience  */
D1::D1(){
    add_func("d11", &D1::f11);
    add_func("d12", &D1::f12);
};
D1::~D1(){};
D2::D2(){
    add_func("d21", &D2::f21);
    add_func("d22", &D2::f22);
};
D2::~D2(){};


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "D.h"

int main()
{
    D1  x1, x11;
    D1* px1=&x1;
    D2  x2;
    D2* px2=&x1;
    void *v;

    // do callbacks ()
    D::stat_dofunc("d11", v);   // will do x1.f11(v)
    D::stat_dofunc("d12", v);   // will do x1.f12(v)
    D::stat_dofunc("d21", v);   // will do x2.f21(v)
    D::stat_dofunc("d22", v);   // will do x2.f22(v)

    // or maybe:
    x11.add_func("do_d11", &D1::f11);
    D::stat_dofunc("do_d11", v);    // x11.f11(v)

} 


The trick here is the d_info struct . It saves a pointer to the actual instantiated object, which also provides implicitly the derived class type, and also a pointer to the appropriate class member and its class type. With that info, the static stat_dofunc can use smart pointers to the right class object, and the right class member function. Voila!

All of this is for (as mentioned previously) using a 3rd party "C" callback. It requires a pointer to a function that it calls at the appropriate time (only passing a string along as data). The static stat_dofunc is that function, that can be called from a "C" program library.

Comments?
Why do you need the D*? Is this not sufficient, or are you concerned with object slicing?

Apparently it is valid to convert a pointer-to-member to pointer-to-member-of-base, subject to the caveat:
- The base class type must be accessible, nonvirtual, and nonambiguous
http://eel.is/c++draft/conv.mem#2.sentence-2

(I guess you knew that, even though you didn't say so in so many words.)

TIL, thanks!
Last edited on
mbozzi wrote:
Why do you need the D*? Is this not sufficient, or are you concerned with object slicing?


Which D*? If in using funct_t, that's because the compiler gripes about non-static member functions in stat_dofunc. Essentially, use explicit cast to func_t for anything the compiler gripes about :-). Amazingly, it does work!

Definitely solved for me.

thx for the help.

ken
Topic archived. No new replies allowed.