How to instantiate a member function pointer?

心已入冬 提交于 2019-12-10 11:03:53

问题


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();
}

回答1:


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();
}



回答2:


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.




回答3:


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.




回答4:


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);
}


来源:https://stackoverflow.com/questions/40704924/how-to-instantiate-a-member-function-pointer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!