假设我有以下代码
template<class MemberFunc>
class Foo {
MyClass object_;
void call() {
auto ptr = MemberFunc{};
(object_.*ptr)();
}
};
int main() {
Foo<decltype(&MyClass::doThings)> foo;
foo.call();
}
这段代码确实崩溃了,因为ptr是0.为什么成员函数构造函数返回0?
我的解决方法如下,但它涉及代码重复。没有其他方法可以从类型构造/实例化成员函数吗? C ++ 14欢迎。
template<class MemberFunc, MemberFunc f>
class Foo {
MyClass object_;
void call() {
(object_.*f)();
}
};
int main() {
Foo<decltype(&MyClass::doThings), &MyClass::doThings> foo;
foo.call();
}
答案 0 :(得分:4)
为什么成员函数构造函数返回0?
因为它指针(-to-member-function)和所有标量类型值初始化为0(C ++ 14 [dcl.init] /8.4)。
没有其他方法可以从类型构造/实例化成员函数吗?
您可以拥有多个具有相同签名的成员函数;怎么知道你想引用哪个成员函数?
您拥有的代码适用于C ++ 14。在C ++ 17中,它可以缩短为以下内容:
template<auto f>
class Foo {
MyClass object_;
void call() {
(object_.*f)();
}
};
int main() {
Foo<&MyClass::doThings> foo;
foo.call();
}
答案 1 :(得分:1)
您无法从其类型中实例化成员函数。例如,请考虑以下类:
struct foo
{
void bar(int){}
void baz(int){}
};
假设您有void (foo::*)(int)
类型。您希望从中获得哪些功能?
从C ++ 1z开始,您将能够使用auto
来推断非类型的非模板模板参数:
template<auto f>
class Foo {
MyClass object_;
void call() {
(object_.*f)();
}
};
int main() {
Foo<&MyClass::doThings> foo;
foo.call();
}
我能想到的C ++ 11/14的唯一解决方法是使用宏:
#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();
}
但出于可读性的原因,我建议不要使用它。
答案 2 :(得分:0)
decltype
返回其参数的类型。使用以下示例:
class MyClass {
public:
int foo();
int bar();
};
两个
decltype(&MyClass::foo);
和
decltype(&MyClass::bar);
的类型相同:int (MyClass::*)()
。
默认初始化此类型时,默认初始化结果为nullptr
。因此崩溃。
答案 3 :(得分:0)
当你初始化一个指向成员函数的指针时,你当然会收到一个nullptr。
顺便说一句,您可以使用与Sam的答案中相同的类型具有多个成员函数。
我不知道为什么你需要将MemberFunc
放到Foo
的模板参数列表中。
但是,如果你想创建一个函数来调用它,这可能是C ++之前C ++中更好的方法(在C ++中使用auto
1z更能匹配这个问题):
class Foo {
MyClass object_;
public:
template<class MemberFunc>
void call(MemberFunc ptr) {
(object_.*ptr)();
}
};
int main() {
Foo foo;
foo.call(&MyClass::doThings);
}