Reputation: 41
My question is: how do I pass a class member function into for_each
Code I am trying to get to work: (works when function is defined outside of class)
The part which fails is commented out - the one using for_each with function as the class member function
Any advice on how to get this to work?
#include <iostream>
#include <algorithm>
#include <vector>
void my_function(std::string str)
{
std::cout << "processing settings: " << str << std::endl;
}
class Settings_vector{
public:
std::vector <std::string> settings;
Settings_vector(){ // push back vector of objects
settings.push_back("settings 1");
settings.push_back("settings 2");
settings.push_back("settings 3");
settings.push_back("settings 4");
}
void tester(std::string settings_string){
std::cout << "processing settings: " << settings_string << std::endl;
}
};
int main()
{
//std::vector<std::string> my_vector;
Settings_vector settings_vector;
std:: cout << "doing things the non-class way\n" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), my_function); // testing function
// WORKS
/*
std:: cout << "doing things the modern way\n" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), settings_vector.tester); // testing function
// FAILS
*/
std:: cout << "doing things the oldskool way\n" << std::endl;
for (int i = 0;i<settings_vector.settings.size();++i) {
settings_vector.tester(settings_vector.settings[i]);
}
// WORKS
return 0;
}
Upvotes: 3
Views: 1683
Reputation: 61
For a more concise sintax, use a static class method. I've slightly edited your code for improved readability within the context of your question (aka removing distractions).
#include <iostream>
#include <vector>
class Settings {
public:
std::vector <std::string> settings;
Settings(std::initializer_list<std::string> l)
: settings(l) {
}
static void tester(std::string const& str) {
std::cout << "processing settings: " << str << std::endl;
}
};
int main() {
Settings sv {"settings 1", "settings 2", "settings 3", "settings 4"};
for_each(sv.settings.begin(), sv.settings.end(), Settings::tester);
return 0;
}
Upvotes: 0
Reputation: 5673
The easiest way would be to use a lambda expression. A bit more complex approach is to use std::bind()
to bind all known arguments (here the instance of the class to the member function) and leave unknown arguments with placeholders _1
, _2
, etc.
#include <iostream>
#include <algorithm>
#include <vector>
class Settings_vector
{
Settings_vector()
: settings { "settings 1"
, "settings 2"
, "settings 3"
, "settings 4"
}
{}
void tester(std::string settings_string)
{ std::cout << "processing settings: " << settings_string << std::endl; }
public:
std::vector <std::string> settings;
};
int main()
{
Settings_vector settings_vector;
using namespace std;
using namespace std::placeholders; // for _1
// Possibility Nr. 1: Use a Lambda Function
for_each( settings_vector.settings.begin(), settings_vector.settings.end()
, [&settings_vector](auto input){ settings_vector.tester(input); }
)
;
// Possibility Nr. 2: Partially bind existing arguments and use placeholders for others
for_each( settings_vector.settings.begin(), settings_vector.settings.end()
, std::bind(&Settings_vector::tester, &settings_vector, _1);
)
;
return 0;
}
Explanations:
I think a lambda is straight forward. In the square brackets, you declare what goes into a closure. Here we pass settings_vector
. Preceding it with &
means that this instance is passed by reference. In the parenthesis, we declare the parameters to the function. I cheated a little bit, as auto
in lambda expressions was introduced in C++14, but you can write it as type std::string
as well.
std::bind()
binds parameters to a function pointer and returns a callable object. If all parameters are present, the returned callable has no parameters and can be called like: callable()
. Here, we want a callable to accept the result of the iteration. Thus, we use a placeholder _1
, which states that this argument will be changed at call-time. Now 2 things remain:
Getting a pointer to a member function. This is done by using &TypeName::MemberName
, in this case &Settings_vector::tester
.
Passing a this
pointer to a member function call: &settings_vector
. When calling a member function, an object must be passed for which this member function is called. Because we just got a pointer to a member function without any bound object to it, that's why the second param is &settings_vector
.
Upvotes: 6