I am trying to write this function:
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);
}
I am having difficulty in passing a function to it:
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");
At the moment I am not passing a function:
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);
}
}
Can you see what I am trying to do? I had hoped to avoid the if/else
ladder because eventually I will have more functions to add to the ladder for other assignments. I had hoped I could pass them as a function.
CodePudding user response:
In order make a method of a class callable, you must supply a this
object.
Wrapping such a method in a std::function
can be done in 2 ways. Both of them associate a specific class instance with a method, making it callable:
Use
std::bind
- see the documentation: std::bind, and a specific stackoverflow post regarding this issue: Using generic std::function objects with member functions in one class.Use lambda functions, that keep the
this
context as a data member of the lambda object. See some general info here: What is a lambda expression in C 11?.
The code below demonstrates this 2 ways.
I used std::string
instead of MFC's CString
, but the principle is the same.
#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;
}
The output:
A::Do1
A::Do2
A::Do3
A::Do1
A::Do2
A::Do3
UPDATE:
Following the OP's question in the comment below:
In order to let you determine the instance to apply the method inside Perform
, you can use pointer to method. The downside is that the method you pass must be of a specified class (A
in my example below). I.e. you loose the ability to pass callables from various classes (or global).
See the code example below:
#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;
}
You can see some more examples here: Calling C member functions via a function pointer.