将 class 的方法作为 std::function 参数传递时出现问题
Problem passing a method of a class as a std::function parameter
我正在尝试编写这个函数:
void CChristianLifeMinistryEditorDlg::PerformAutoAssignForAssignment(
const MSAToolsLibrary::AssignmentType eAssignType,
const CString strStartingName,
std::function<void(CString)> funcSetAssignName)
{
CString strName = L"abc";
CChristianLifeMinistryEntry *pEntry = xxx;
// ...
pEntry->funcSetAssignName(strName);
}
我很难将函数传递给它:
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_Host, L"Name 1" );
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_CoHost, L"Name 2");
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_ConductorCBS, L"Name 3");
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_ReaderCBS, L"Name 4");
目前我没有传递函数:
void CChristianLifeMinistryEditorDlg::PerformAutoAssignForAssignment(
const MSAToolsLibrary::AssignmentType eAssignType,
const CString strStartingName)
{
CString strName = L"abc";
CChristianLifeMinistryEntry *pEntry = xxx;
// ...
pEntry->funcSetAssignName(strName);
if (eAssignType == MSAToolsLibrary::AssignmentType_ConductorCBS)
{
pEntry->SetCBSConductor(strNameToUse);
}
else if (eAssignType == MSAToolsLibrary::AssignmentType_ReaderCBS)
{
pEntry->SetCBSReader(strNameToUse);
}
else if (eAssignType == MSAToolsLibrary::AssignmentType_Host)
{
pEntry->SetVideoHost(strNameToUse);
}
else if (eAssignType == MSAToolsLibrary::AssignmentType_CoHost)
{
pEntry->SetVideoCohost(strNameToUse);
}
}
你能看出我在做什么吗?我曾希望避免使用 if/else
阶梯,因为最终我将有更多功能添加到阶梯以用于其他作业。我曾希望我可以将它们作为函数传递。
为了使 class 的方法可调用,您必须提供 this
对象。
可以通过两种方式将这种方法包装在 std::function
中。它们都将特定的 class 实例与方法相关联,使其可调用:
使用 std::bind
- 请参阅文档:std::bind, and a specific Whosebug post regarding this issue: Using generic std::function objects with member functions in one class.
使用 lambda 函数,将 this
上下文作为 lambda 对象的数据成员。在此处查看一些一般信息:What is a lambda expression in C++11?.
下面的代码演示了这两种方式。
我用的是std::string
而不是MFC的CString
,但是原理是一样的
#include <iostream>
#include <string>
#include <functional>
struct A
{
void Do1(std::string const & str) { std::cout << "A::Do1" << std::endl; };
void Do2(std::string const & str) { std::cout << "A::Do2" << std::endl; };
void Do3(std::string const & str) { std::cout << "A::Do3" << std::endl; };
};
struct Dlg
{
A a;
void Perform(std::string const & str, std::function<void(std::string)> funcSetAssignName)
{
funcSetAssignName(str);
}
void m()
{
std::string str = "abc";
// Pass method as std::function using std::bind:
Perform(str, std::bind(&A::Do1, a, std::placeholders::_1));
Perform(str, std::bind(&A::Do2, a, std::placeholders::_1));
Perform(str, std::bind(&A::Do3, a, std::placeholders::_1));
// Pass method as std::function using lambdas:
Perform(str, [this](std::string const & str) { this->a.Do1(str); });
Perform(str, [this](std::string const & str) { this->a.Do2(str); });
Perform(str, [this](std::string const & str) { this->a.Do3(str); });
}
};
int main()
{
Dlg dlg;
dlg.m();
return 0;
}
输出:
A::Do1
A::Do2
A::Do3
A::Do1
A::Do2
A::Do3
更新:
在下面的评论中关注 OP 的问题:
为了让您确定在Perform
中应用方法的实例,您可以使用指向方法的指针。缺点是您传递的方法必须是指定的 class(在我下面的示例中为 A
)。 IE。你失去了从各种classes(或全局)传递可调用文件的能力。
参见下面的代码示例:
#include <iostream>
#include <string>
struct A
{
void Do1(std::string const & str) { std::cout << "A::Do1" << std::endl; };
void Do2(std::string const & str) { std::cout << "A::Do2" << std::endl; };
void Do3(std::string const & str) { std::cout << "A::Do3" << std::endl; };
};
struct Dlg
{
A a;
void Perform(std::string const & str, void (A::*funcSetAssignName)(std::string const & str))
{
// Here the instance for class A can be determined (I simply used `a`):
(a.*funcSetAssignName)(str);
}
void m()
{
std::string str = "abc";
// Pass pointer to method:
Perform(str, &A::Do1);
Perform(str, &A::Do2);
Perform(str, &A::Do3);
}
};
int main()
{
Dlg dlg;
dlg.m();
return 0;
}
您可以在此处查看更多示例:Calling C++ member functions via a function pointer。
我正在尝试编写这个函数:
void CChristianLifeMinistryEditorDlg::PerformAutoAssignForAssignment(
const MSAToolsLibrary::AssignmentType eAssignType,
const CString strStartingName,
std::function<void(CString)> funcSetAssignName)
{
CString strName = L"abc";
CChristianLifeMinistryEntry *pEntry = xxx;
// ...
pEntry->funcSetAssignName(strName);
}
我很难将函数传递给它:
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_Host, L"Name 1" );
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_CoHost, L"Name 2");
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_ConductorCBS, L"Name 3");
PerformAutoAssignForAssignment(MSAToolsLibrary::AssignmentType_ReaderCBS, L"Name 4");
目前我没有传递函数:
void CChristianLifeMinistryEditorDlg::PerformAutoAssignForAssignment(
const MSAToolsLibrary::AssignmentType eAssignType,
const CString strStartingName)
{
CString strName = L"abc";
CChristianLifeMinistryEntry *pEntry = xxx;
// ...
pEntry->funcSetAssignName(strName);
if (eAssignType == MSAToolsLibrary::AssignmentType_ConductorCBS)
{
pEntry->SetCBSConductor(strNameToUse);
}
else if (eAssignType == MSAToolsLibrary::AssignmentType_ReaderCBS)
{
pEntry->SetCBSReader(strNameToUse);
}
else if (eAssignType == MSAToolsLibrary::AssignmentType_Host)
{
pEntry->SetVideoHost(strNameToUse);
}
else if (eAssignType == MSAToolsLibrary::AssignmentType_CoHost)
{
pEntry->SetVideoCohost(strNameToUse);
}
}
你能看出我在做什么吗?我曾希望避免使用 if/else
阶梯,因为最终我将有更多功能添加到阶梯以用于其他作业。我曾希望我可以将它们作为函数传递。
为了使 class 的方法可调用,您必须提供 this
对象。
可以通过两种方式将这种方法包装在 std::function
中。它们都将特定的 class 实例与方法相关联,使其可调用:
使用
std::bind
- 请参阅文档:std::bind, and a specific Whosebug post regarding this issue: Using generic std::function objects with member functions in one class.使用 lambda 函数,将
this
上下文作为 lambda 对象的数据成员。在此处查看一些一般信息:What is a lambda expression in C++11?.
下面的代码演示了这两种方式。
我用的是std::string
而不是MFC的CString
,但是原理是一样的
#include <iostream>
#include <string>
#include <functional>
struct A
{
void Do1(std::string const & str) { std::cout << "A::Do1" << std::endl; };
void Do2(std::string const & str) { std::cout << "A::Do2" << std::endl; };
void Do3(std::string const & str) { std::cout << "A::Do3" << std::endl; };
};
struct Dlg
{
A a;
void Perform(std::string const & str, std::function<void(std::string)> funcSetAssignName)
{
funcSetAssignName(str);
}
void m()
{
std::string str = "abc";
// Pass method as std::function using std::bind:
Perform(str, std::bind(&A::Do1, a, std::placeholders::_1));
Perform(str, std::bind(&A::Do2, a, std::placeholders::_1));
Perform(str, std::bind(&A::Do3, a, std::placeholders::_1));
// Pass method as std::function using lambdas:
Perform(str, [this](std::string const & str) { this->a.Do1(str); });
Perform(str, [this](std::string const & str) { this->a.Do2(str); });
Perform(str, [this](std::string const & str) { this->a.Do3(str); });
}
};
int main()
{
Dlg dlg;
dlg.m();
return 0;
}
输出:
A::Do1
A::Do2
A::Do3
A::Do1
A::Do2
A::Do3
更新:
在下面的评论中关注 OP 的问题:
为了让您确定在Perform
中应用方法的实例,您可以使用指向方法的指针。缺点是您传递的方法必须是指定的 class(在我下面的示例中为 A
)。 IE。你失去了从各种classes(或全局)传递可调用文件的能力。
参见下面的代码示例:
#include <iostream>
#include <string>
struct A
{
void Do1(std::string const & str) { std::cout << "A::Do1" << std::endl; };
void Do2(std::string const & str) { std::cout << "A::Do2" << std::endl; };
void Do3(std::string const & str) { std::cout << "A::Do3" << std::endl; };
};
struct Dlg
{
A a;
void Perform(std::string const & str, void (A::*funcSetAssignName)(std::string const & str))
{
// Here the instance for class A can be determined (I simply used `a`):
(a.*funcSetAssignName)(str);
}
void m()
{
std::string str = "abc";
// Pass pointer to method:
Perform(str, &A::Do1);
Perform(str, &A::Do2);
Perform(str, &A::Do3);
}
};
int main()
{
Dlg dlg;
dlg.m();
return 0;
}
您可以在此处查看更多示例:Calling C++ member functions via a function pointer。