在成员初始化列表中使用 std::function
Using std::function in member initialization list
我有一个类型定义:
typedef S32(iMyDataClass1::*getDataFunction_t)(void);
还有一个类型:
struct functionMap_t {
std::vector<getDataFunction_t> pDataFunctionTable;
struct dataRequestor_t dataRequestor;
};
然后我有一个成员变量:
functionMap_t FnMap1;
然后我在成员初始值设定项列表中设置:
myClass::myClass() : FnMap1({
{
&iMyDataClass1::getData1,
&iMyDataClass1::getData2,
&iMyDataClass1::getData3
},
dataRequestor1
})
然后我在构造函数中使用:
addNewFnMap(FnMap1);
一切正常。不幸的是,它不能扩展到不同 类 的函数指针,因为 getDataFunction_t
绑定到 iMyDataClass1
中的指针
我尝试使用模板,但 运行 遇到了我无法解决的问题。现在我正在尝试使用 std::function
,这意味着我将原来的 typedef 更改为(我认为):
typedef std::function<S32(void)> getDataFunction_t;
在这种情况下设置初始化列表的正确方法是什么?我在这里使用 std::bind
吗?
更新:
这是我对新的初始化列表的尝试。我不知道这是否正确,但这是我在发布此问题之前所做的:
{
{
(std::bind(&iMyDataClass1::getData1, functionToFetchCorrectObject())),
(std::bind(&iMyDataClass1::getData2, functionToFetchCorrectObject())),
(std::bind(&iMyDataClass1::getData3, functionToFetchCorrectObject()))
},
PGN65370
}
您可以使用 lambda 表达式。但是,如果您想将签名保留为 std::function<S32(void)>
,则需要捕获您的对象。
myClass::myClass() : FnMap1({
{
[this](){ return getData1(); },
[this](){ return getData2(); },
[this](){ return getData3(); },
},
dataRequestor1
})
如果您不想这样做,您可以更改签名以将 this
指针作为参数传递给您的回调。但正如 Barry 在评论中指出的那样,这不允许您将对不同 类 的回调放入同一个 vector
。您可以 reinterpret_cast
lambda 内部的指针,但除了丑陋和危险之外,调用者如何知道要传入哪个指针?
如果你想让它与不同的 classes 一起工作,你可以简单地存储带有你想要的任何签名的可调用文件:
struct functionMap_t {
std::vector<std::function<S32(void)>> pDataFunctionTable;
struct dataRequestor_t dataRequestor;
};
接下来,我可能会做的是为 class 高阶函数提供 return std::functions 正确的签名。
std::function<S32(void)> iMyDataClass1::getData1Getter() {
auto f = [this] () {return this->getData1()};
return f;
}
现在您可以非常简单地进行初始化:
iMyDataClass1 o;
...
FnMap1({o.getData1Getter(), ..., dataRequestor1});
此代码未经仔细检查,我确定它包含语法错误。但它应该给你它的要点。主要思想是:如果你想使用可能附加或不附加到特定对象的函数,那么你需要使用函数(实际上是闭包本身)。以这种方式使用函数激发了使用高阶函数的设计,从一个上下文到 returns 函数并将它们传递给另一个上下文。
编辑:我最近与某人就 C++11 中的观察者模式进行了一些设计对话。我建议做一些与此非常相似的事情,避免使用多态性,保持通用和解耦,并避免污染继承层次结构真的很好。
我有一个类型定义:
typedef S32(iMyDataClass1::*getDataFunction_t)(void);
还有一个类型:
struct functionMap_t {
std::vector<getDataFunction_t> pDataFunctionTable;
struct dataRequestor_t dataRequestor;
};
然后我有一个成员变量:
functionMap_t FnMap1;
然后我在成员初始值设定项列表中设置:
myClass::myClass() : FnMap1({
{
&iMyDataClass1::getData1,
&iMyDataClass1::getData2,
&iMyDataClass1::getData3
},
dataRequestor1
})
然后我在构造函数中使用:
addNewFnMap(FnMap1);
一切正常。不幸的是,它不能扩展到不同 类 的函数指针,因为 getDataFunction_t
绑定到 iMyDataClass1
我尝试使用模板,但 运行 遇到了我无法解决的问题。现在我正在尝试使用 std::function
,这意味着我将原来的 typedef 更改为(我认为):
typedef std::function<S32(void)> getDataFunction_t;
在这种情况下设置初始化列表的正确方法是什么?我在这里使用 std::bind
吗?
更新: 这是我对新的初始化列表的尝试。我不知道这是否正确,但这是我在发布此问题之前所做的:
{
{
(std::bind(&iMyDataClass1::getData1, functionToFetchCorrectObject())),
(std::bind(&iMyDataClass1::getData2, functionToFetchCorrectObject())),
(std::bind(&iMyDataClass1::getData3, functionToFetchCorrectObject()))
},
PGN65370
}
您可以使用 lambda 表达式。但是,如果您想将签名保留为 std::function<S32(void)>
,则需要捕获您的对象。
myClass::myClass() : FnMap1({
{
[this](){ return getData1(); },
[this](){ return getData2(); },
[this](){ return getData3(); },
},
dataRequestor1
})
如果您不想这样做,您可以更改签名以将 this
指针作为参数传递给您的回调。但正如 Barry 在评论中指出的那样,这不允许您将对不同 类 的回调放入同一个 vector
。您可以 reinterpret_cast
lambda 内部的指针,但除了丑陋和危险之外,调用者如何知道要传入哪个指针?
如果你想让它与不同的 classes 一起工作,你可以简单地存储带有你想要的任何签名的可调用文件:
struct functionMap_t {
std::vector<std::function<S32(void)>> pDataFunctionTable;
struct dataRequestor_t dataRequestor;
};
接下来,我可能会做的是为 class 高阶函数提供 return std::functions 正确的签名。
std::function<S32(void)> iMyDataClass1::getData1Getter() {
auto f = [this] () {return this->getData1()};
return f;
}
现在您可以非常简单地进行初始化:
iMyDataClass1 o;
...
FnMap1({o.getData1Getter(), ..., dataRequestor1});
此代码未经仔细检查,我确定它包含语法错误。但它应该给你它的要点。主要思想是:如果你想使用可能附加或不附加到特定对象的函数,那么你需要使用函数(实际上是闭包本身)。以这种方式使用函数激发了使用高阶函数的设计,从一个上下文到 returns 函数并将它们传递给另一个上下文。
编辑:我最近与某人就 C++11 中的观察者模式进行了一些设计对话。我建议做一些与此非常相似的事情,避免使用多态性,保持通用和解耦,并避免污染继承层次结构真的很好。