La mia domanda è: come faccio a passare una funzione membro della classe in for_each
Codice Sto cercando di mettermi al lavoro: (funziona quando la funzione è definita al di fuori della classe)
La parte che fallisce è commentata - quella che usa for_each con la funzione come funzione membro della classe
Qualche consiglio su come farlo funzionare?
#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 wayn" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), my_function); // testing function
// WORKS
/*
std:: cout << "doing things the modern wayn" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), settings_vector.tester); // testing function
// FAILS
*/
std:: cout << "doing things the oldskool wayn" << std::endl;
for (int i = 0;i<settings_vector.settings.size();++i) {
settings_vector.tester(settings_vector.settings[i]);
}
// WORKS
return 0;
}
risposte:
6 per risposta № 1Il modo più semplice sarebbe usare un'espressione lambda. Un approccio un po 'più complesso è quello di usare std::bind()
associare tutti gli argomenti noti (qui l'istanza della classe alla funzione membro) e lasciare argomenti sconosciuti con i segnaposto _1
, _2
, eccetera.
#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;
}
spiegazioni:
Penso che un lambda sia diretto. Nelle parentesi quadre, dichiari ciò che entra in una chiusura. Qui passiamo
settings_vector
. Precedendolo con&
significa che questa istanza viene passata per riferimento. In parentesi, dichiariamo i parametri per la funzione. Ho barato un po ', comeauto
nelle espressioni lambda è stato introdotto in C ++ 14, ma è possibile scriverlo come tipostd::string
anche.std::bind()
lega i parametri a un puntatore di funzione e restituisce un oggetto callable. Se tutti i parametri sono presenti, il callable restituito non ha parametri e può essere chiamato come:callable()
. Qui, vogliamo un callable per accettare il risultato dell'iterazione. Quindi, usiamo un segnaposto_1
, che afferma che questo argomento verrà modificato al momento della chiamata. Ora rimangono 2 cose:Ottenere un puntatore a una funzione membro. Questo è fatto usando
&TypeName::MemberName
, in questo caso&Settings_vector::tester
.Passando a
this
puntatore a una chiamata di funzione membro:&settings_vector
. Quando si chiama una funzione membro, un oggetto deveessere passato per il quale viene chiamata questa funzione membro. Poiché abbiamo appena ottenuto un puntatore a una funzione membro senza alcun oggetto associato, è per questo che è il secondo parametro&settings_vector
.