Alexander Theißen
Alexander Theißen

Reputation: 3889

How to instantiate a member function pointer?

Lets say I have the follow code

template<class MemberFunc>
class Foo {
  MyClass object_;
  void call() {
    auto ptr = MemberFunc{};
    (object_.*ptr)();
  }
};


int main() {
  Foo<decltype(&MyClass::doThings)> foo;
  foo.call();
}

This code does crash for me because ptr is 0. Why does the member function constructor returns 0?

My workaround is the following but it involves code duplication. Is there no other way to just construct/instantiate the member function from the type? C++14 welcome.

template<class MemberFunc, MemberFunc f> 
class Foo {
  MyClass object_;
  void call() {
    (object_.*f)();
  }
};


int main() {
  Foo<decltype(&MyClass::doThings), &MyClass::doThings> foo;
  foo.call();
}

Upvotes: 2

Views: 429

Answers (4)

Danh
Danh

Reputation: 6016

When you value-initialize a pointer to member-function, you will receive a nullptr, of course.

By the way, you can have multiple member function with the same type as you can see in Sam's answer.

I don't know why do you need to put the MemberFunc to template parameter list of Foo.

However, if you want to make a function to call it, this maybe a better approach in C++ before C++1z (use auto in C++1z is better match for this question):

class Foo {
  MyClass object_;
public:
  template<class MemberFunc>
  void call(MemberFunc ptr) {
    (object_.*ptr)();
  }
};
int main() {
  Foo foo;
  foo.call(&MyClass::doThings);
}

Upvotes: 0

krzaq
krzaq

Reputation: 16421

You can't instantiate a member function from its type. For example, consider the following class:

struct foo
{
    void bar(int){}
    void baz(int){}
};

Suppose you have a type void (foo::*)(int). Which function would you like to get from it?

As of C++1z, you'll be able to use auto to deduce non-type, non-template template parameters:

template<auto f> 
class Foo {
  MyClass object_;
  void call() {
    (object_.*f)();
  }
};


int main() {
  Foo<&MyClass::doThings> foo;
  foo.call();
}

demo


The only workaround for C++11/14 I can think of is using a macro:

#define type_value_pair(x) decltype(x), x
template<class MemberFunc, MemberFunc f> 
class Foo {
  MyClass object_;
  void call() {
    (object_.*f)();
  }
};


int main() {
  Foo<type_value_pair(&MyClass::doThings)> foo;
  foo.call();
}

demo

But I'd advise against using this, for readability reasons.

Upvotes: 1

ildjarn
ildjarn

Reputation: 62975

Why does the member function constructor returns 0?

Because it's a pointer (-to-member-function), and all scalar types value-initialize to 0 (C++14 [dcl.init]/8.4).

Is there no other way to just construct/instantiate the member function from the type?

You can have multiple member functions with the same signature; how would it know which member function you want to refer to?

The code you have is fine for C++14. In C++17, it can be shortened to the following:

template<auto f> 
class Foo {
  MyClass object_;
  void call() {
    (object_.*f)();
  }
};

int main() {
  Foo<&MyClass::doThings> foo;
  foo.call();
}

Upvotes: 4

Sam Varshavchik
Sam Varshavchik

Reputation: 118340

decltype returns the type of its argument. Using the following example:

class MyClass {

public:
    int foo();
    int bar();
};

Both

decltype(&MyClass::foo);

and

decltype(&MyClass::bar);

is the same type: int (MyClass::*)().

When you default-initialize this type, the default initialization results in a nullptr. Hence the crash.

Upvotes: 0

Related Questions