Reputation: 3889
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
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
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();
}
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();
}
But I'd advise against using this, for readability reasons.
Upvotes: 1
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
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