我正在使用支持C ++ 11的ARM微控制器和编译器
我的课程描述如下:
class commands
{
public:
string cmd_str;
void (*fktPtr)(void);
};
diag对象是Diag Class的一部分
class Diag
{
public:
void reset(void);
}
Diag diag;
切换功能是代码中的独立功能:
void toggle_pin(void);
然后我定义了一个名为cmdlist的命令向量:
vector<commands> cmdlist = {
{"togg", toggle_pin }, // this works
{"rst", diag.reset}, // this gives an error. why ?
{"rst1", [](){diag.reset();}}, // this also works
}
错误:
main.cpp:81:1: error: could not convert '{{"togg", toggle_pin}, {"rst", diag.Diag::reset}}, {"rst1",<lambda closure object><lambda()>{}} from '<brace-enclosed initializer list>' to 'std::vector<commands>'
为什么没有来自对象的初始化列表支持方法,但是支持常规函数/ lambda函数?
答案 0 :(得分:5)
它与初始化列表或向量无关,您可以从
获得相同的错误void (*fktPtr)(void) = diag.reset;
你有两个问题,一个是缺少&
来创建一个函数指针。裸函数隐式转换为函数指针;成员函数没有这样的转换。
那么我们就有了:
void (*fktPtr1)(void) = &toggle_pin; // works
void (*fktPtr2)(void) = &Diag::reset; // doesn't
现在,您遇到了类型不兼容的问题。非静态成员函数的地址具有类型指向成员函数的指针,与裸函数和静态成员函数不同(这些函数仍然需要显式&ClassName::FunctionName
,但产生正常的函数指针)。您无法将指向成员的指针转换为普通函数指针。
部分问题是指向成员的函数需要一个目标对象(有时称为隐藏this
参数)。提前设置C ++的方法是std::bind
,但你仍然没有得到普通的函数指针。
lambda导致一个普通的函数(指针最终在你的向量中),它从全局变量中检索目标对象并在其上调用一个函数。这是合法的,但可能根本没有类,因为你被锁定到全局变量命名的单个实例。
如果您想要更接近C#等语言中的“委托”,将函数和目标对象存储在一起,请尝试
std::function<void (void)> fktPtr;
而不是裸函数指针。这与裸函数,静态成员函数,绑定实例成员函数,非捕获lambdas和捕获lambda都兼容。