how to initialize a pointer to a function inside a class that is used as value in a map? - c++

I am writing a program whose behaviour is to be controlled by user-defined settings, provided through a plain ASCII configuration file including keywords and values.
Since not all keywords may be provided by the user, there are also "built-in" settings.
The configuration values provided for different keywords will affect variables (all part of settings class) that will, in turn, determine the program's behaviour.
To translate the configuration values to these variables, I want to use parsing functions - one per configuration keyword.
To achieve this, I use a map, with a configuration keyword as a key, and a param_struct object as a value.
param_struct contains the default value for the configuration keyword, the value read from configuration file (which may be empty), and a pointer to a parsing function.
As a first step, I am trying to initialize the default values, but I keep getting compilation errors. Is there anything am I doing fundamentally wrong here?
settings.cpp: In member function 'std::map<std::__cxx11::basic_string<char>, param_struct> settings::create_builtin_config()':
settings.cpp:84:96: error: no matching function for call to 'param_struct::param_struct(const char [6], const char [1], <unresolved overloaded function type>)'
84 | map<string, param_struct> builtin_config = {{"MY_CONFIG_KEYWORD", param_struct("XYZZY","", update_log)}}; //
| ^
settings.cpp:84:98: error: could not convert '{{"MY_CONFIG_KEYWORD", <expression error>}}' from '<brace-enclosed initializer list>' to 'std::map<std::__cxx11::basic_string<char>, param_struct>'
84 | map<string, param_struct> builtin_config = {{"MY_CONFIG_KEYWORD", param_struct("XYZZY","", update_log)}}; //
| ^
| |
| <brace-enclosed initializer list>
// settings.h file
typedef void (*param_setter) (string, string);
class param_struct {
string default_value; // built-in default configuration value
string loaded_value; // configuration value loaded from the
param_setter parsing_function;
// param_setter parsing_function; // pointer to the respective parsing/initialization function
public:
friend class settings;
param_struct();
param_struct(string, string, param_setter);
~param_struct();
};
class settings {
map<string,param_struct> config_params; // keywords and the respective values + parsing/initialization functions
/* lots of other declarations skipped */
map <string, param_struct> create_builtin_config();
public:
void update_log(string builtin_param, string user_param); // dummy function that does nothing, except writing a log entry. used to test config parameter parsing
friend class param_struct;
}
//settings.cpp file:
settings::settings() {
config_params = create_builtin_config();
}
map<string, param_struct> settings::create_builtin_config() {
map<string, param_struct> builtin_config = {{"MY_CONFIG_KEYWORD", param_struct("XYZZY","", update_log)}}; //
return builtin_config;
}
param_struct::param_struct(string defaultval, string loaded, param_setter parser_fn) {
default_value = defaultval;
loaded_value = loaded;
parsing_function = parser_fn;
}

update_log is a member function.
Your param_setter type is a free function.
They don't match.
A member function has an implicit first argument -- a pointer to the class -- and isn't compatibile with free function pointers.
The easy solution is to store a std::function<void(string,string)>, then pass in [this](string s1, string s2){ update_log(s1, s2); }. This also makes explicit that you are passing in a pointer to the object here; as you are storing it, you'll want to delete your move/copy construct/assignment operators, or you'll get very surprising results.
Another option is to make update_log a static member function, which is compatible with a free function of the same signature. You lose access to the state of your class object, however.

Related

Is there have a way to delay type binding at code level in C++?

I'm going to request some user configuration via json from the server that contains two types of data like (usrID, bool), and (usrID, int). so, I created two map to classify and reload two functions with the same name to put the data into the corresponding map after parsed.
For the sake of refinement, I used the auto keyword of C++11 to initialize a variable without assign and determined its type whether bool or int mentioned above through assigned by parse function, so as to call the overloaded function directly to store them.
But it causes compiler error that cannot use a auto variable without assign.
bool fromStringtoBool() {……}
int fromStringtoInt() {……}
void setAppidConfig(int,bool);
void setAppidConfig(int,int);
……
……
void main func()
{
……
int usrId;
auto value;
if(isBool())
{
value = fromStringtoBool();
}
else
{
value = fromStringtoInt();
}
setAppidConfig(usrId,value)
……
}
Is it possible to implement the above logic in C++ ?
No. In C++ auto variable type resolution and also function overload resolution has to happen compile time. The isBool() of yours is presumably runtime value. So all you can do is something like:
if(isBool())
{
setAppidConfig(usrId,fromStringtoBool());
}
else
{
setAppidConfig(usrId,fromStringtoInt());
}
auto allows you to omit the type name and let the compiler deduce the type. There is no type to deduce from in your case, since there's no assignment, so nothing can be deduced.
For your use case, you need some kind of variant type that can store one of several types. The Qt library has QVariant, and other libraries usually offer something like that as well. As of C++17 however, such a type is offered directly by the standard library: std::variant.
int usrId;
std::variant<bool, int> value;
if (isBool()) {
value = fromStringtoBool();
} else {
value = fromStringtoInt();
}
setAppidConfig(usrId, value);
The setAppidConfig() function would need to accept an appropriate variant parameter:
void setAppidConfig(int usrId, std::variant<bool, int> value)
{
// ...
if (std::holds_alternative<int>(value)) {
// It's a int.
int i = std::get<int>(value);
} else {
// It's a bool.
bool b = std::get<bool>(value);
}
}
Note that variants can hold more than just two types (you can have an std::variant<bool, int, std::string> for example.)
If you need something that can hold anything, then you can use an std::any. This type does not need to know the types in advance (it takes no template arguments.)

Calling a vector of function pointer

I am trying to use vector of function pointer in C++ which belongs to one class and being called in another class. For example: In class BoundaryCondition (file BoundaryCondition.h), I initialize the function pointer as:
class BoundaryConditions{
public:
// Constructor function
BoundaryConditions(int id = 0);
vector <void (BoundaryConditions::*) (Face &, int, int)> func2bcond;
void fixedValue(Face &face, int id, int rkStep);
// and other functions with similar definition as fixedValue
}
In another class (DG.h), I initialize an array of BoundaryCondition instance, something like
BoundaryCondition *bcond;
and assign memory to bcond variable using new (in file DG.cpp). For each bcond[i] instance, I need to assign memory to function pointer as:
this->bcond[i].func2bcond.resize(totNoOfVariable);
I am using resize instead of pushback as file reading may not be in the required order. Next, I am assigning function to this function pointer (again in DG.cpp) as per my boundary condition file:
bcond[i].func2bcond[j] = (&BoundaryConditions::fixedValue);
The code compiles alright till this point. I am getting error when I try to call these functions. I call this in DG.cpp. The code is as follows:
(bcond[i].*func2bond[j])(f,1,2);
I keep getting the following error:
error: 'func2bcond' was not declared in this scope
I am quite sure it is only matter of position of * or the brackets, but I am stuck here and I did not get any specific solved post on stackoverflow.
Thanks in advance
Pointer on method requires instance when called, so your code might look like:
(bcond[i].*(bcond[i].func2bond[j]))(f, 1, 2);
or, splitting expression:
auto methodPtr = bcond[i].func2bond[j]; // auto is `void (BoundaryConditions::*) (Face &, int, int)`
(bcond[i].*methodPtr)(f, 1, 2);

Using functions from classes

I am learning C++ and very new at using classes, and I am getting very confused in trying to use them. I am trying to convert my existing code (which used structs) so that it uses classes - so while I know what I am trying to do I don't know if I'm doing it correctly.
I was told that when using functions from the class, I first need to instantiate an object of the class. So what I have tried (a snippet) in my main function is:
int main()// line 1
{
string message_fr_client = "test"; //line2
msgInfo message_processed; //line 3
message_processed.incMsgClass(message_fr_client); //line 4
if (!message_processed.priority_check(qos_levels, message_processed)) //line 5
cout << "failure: priority level out of bounds\n"; //line 6
return 0; //line 7
}
Could you help me clarify if my following assumptions are correct? The compiler is not showing any error and so I don't know if it is error-free, or if there are ones lurking beneath.
At line 4, is the function incMsgClass being performed on the string message_fr_client and returning the resultant (and modified) message_processed?
At line 5, the function priority_check is being performed on the message_processed and returning a boolean?
In my class definition, I have a function getPath that is meant to modify the value of nodePath - is it just a matter of using message_processed.getPath(/*arguments*/)?
I haven't included the body of the functions because I know they work - I would just like to find out how the class functions interact. Please let me know if I can be clearer - just trying to clear up some confusion here.
Here is my class:
#ifndef clientMsgHandling_H
#define clientMsgHandling_H
#include <list>
#include <map>
#include <queue>
class msgInfo
{
public:
msgInfo();
msgInfo(int, int, int, std::string, std::list<int>);
/*classifying message*/
msgInfo incMsgClass(std::string original_msg);
/*message error checks*/
bool priority_check(int syst_priority, msgInfo msg); //check that message is within qos levels
bool route_check(std::map<std::pair<int, int>, int> route_table, msgInfo msg); //check that route exists
void getPath(msgInfo msg, std::map<std::pair<int, int>, int> route_info, int max_hop);
private:
int source_id;
int dest_id;
int priority;
std::string payload;
std::list<int> nodePath;
};
#endif
While it may compile (and even run), there are a few oddities with the code as shown:-
First off, class methods know which object they are operating on - so your priority_check and route_check methods probably don't need msgInfo as a parameter.,
for example, your old non-class function might be like this
bool priority_check(int p, msgInfo msg)
{
return msg.priority < p;
}
But the new one should look like this:
bool msgInfo::priority_check(int p)
{
return priority < p;
}
Also, incMsgClass is a bit odd, as it's a non-static class method that returns a msgInfo object. It's difficult to tell without understanding what it's supposed to do, but it seems possible that this function should actually be a constructor, rather than a regular method.
One other thing is that you're currently passing a msgInfo by value to those methods. So if the method needed to modify the passed msgInfo, it would not have any effect. It's generally better to pass objects by reference or const reference to other methods. So, back to the previous non-method example, it should really be this.
bool priority_check(int p, const msgInfo &msg)
...
But, as I said, you probably don't need the msgInfo parameters anyway.
At line 4, is the function incMsgClass being performed on the string message_fr_client
Yes
and returning the resultant (and modified) message_processed?
Whatever it's returning, you're ignoring the return value. It can modify the object itself, yes, because the function is not const.
At line 5, the function priority_check is being performed on the message_processed and returning a boolean?
Yes
In my class definition, I have a function getPath that is meant to modify the value of nodePath - is it just a matter of using message_processed.getPath(/arguments/)?
If a member function is intended to modify one of the class members, it's just a matter of not marking that function const
Hard to tell without implementation-details, but here we go:
I. You are passing a std::string as value (C++ is call-by-value by default), so you get a copy of the std::string in your method. If you want to work on the object you passed and manipulate it, use a reference on the object, like
msgInfo incMsgClass(std::string& original_msg); // notice the ampersand
then you can change your signature to
void incMsgClass(std::string& original_msg);
as you don't need to return the std::string you passed.
II. Yes, at least according to your signature
III. Can see a node_path only as a member.
For all your questions, see C++-FAQ.
Your basic assumptions are correct.
message_processed.incMsgClass(message_fr_client); //line 4
This line is not correct. The function you call returns msgInfo which is simply dropped. You should assign it to something. But it is not as it is usually done. You should make it a constructor of msgInfo, like
class msgInfo
{
public:
msgInfo(std::string original_msg);
...
}
Then you could call it like this
msgInfo message_processed(message_fr_client);
That line would create a msgInfo that is already properly initialized.
There is another pattern for creating class instances - static creating function. In your case you could mark incMsgClass static and then call it like
msgInfo message_processed = msgInfo.incMsgClass(message_fr_client);
I seriously doubt you need this pattern here, so I'd advise to move to constructor.
As of other functions, I see no problems there. Just note that all member functions not marked as const can modify the object they are called on. So, you don't need to pass this object explicitly. For functions a pointer to the object they are called on is available by name this. Also the functions can access all class variables as if these variables are global for normal (non-member) functions.

Using find_if within instance method

I have an instance method that populates a vector of strings. I am trying to find the one vector entry that contains a specific substring (for now, that substring is fixed - simple).
I have a .h:
namespace Data
{
namespace Shared
{
class Logger
{
public:
bool FindLogDirectoryPredicate(const string &str);
int GetLogDirectory(string logConfigFile, string& logDirectory);
...
}
}
}
and .cpp:
#include <algorithm>
#include <vector>
#include "Logger.h"
bool Logger::FindLogDirectoryPredicate(const string &str)
{
// Return false if string found.
return str.find("File=") > 0 ? false : true;
}
int Logger::GetLogDirectory(string logConfigFile, string& logDirectory)
{
vector<string> fileContents;
...
vector<string>::iterator result = find_if(fileContents.begin(), fileContents.end(), FindLogDirectoryPredicate);
...
}
Compiling this in Visual Studio 2010, I receive:
Error 7 error C3867: 'Data::Shared::Logger::FindLogDirectoryPredicate': function call missing argument list; use '&Data::Shared::Logger::FindLogDirectoryPredicate' to create a pointer to member Logger.cpp 317 1 Portability
Throwing an & in front of the function ref in the find_if call then results in:
Error 7 error C2276: '&' : illegal operation on bound member function expression Logger.cpp 317 1 Portability
I did try to put the predicate function outside the class, but that didn't seem to work - gave me a function not found error. Tried qualifying the predicate with the class name... that gave me a different error in algorithm (header):
Error 1 error C2064: term does not evaluate to a function taking 1 arguments c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm 83 1 Portability
The example I was following from here seems to indicate that this is relatively simple.... so what am I doing wrong?
The problem is that FindLogDirectoryPredicate is an instance method: it's not enough to specify its name, you somehow have to specify which object that method should be called on. Now the answer to this question is obvious to us (this), but not to the compiler.
The classic way to do this is with
find_if(fileContents.begin(),
fileContents.end(),
bind1st(mem_fun(&Logger::FindLogDirectoryPredicate), this));
What's going on here?
mem_fun "converts a member function to a function object". That is, it creates an instance of a type (what type exactly is unspecified, but we don't care) that exposes operator() (this is what we do care about!). This operator expects the first parameter to be a pointer to an instance of the type that defines the member function; here, that would be an instance of Logger.
bind1st then takes this function object that takes two parameters (first is the pointer to instance, second is the original const string & parameter) and returns a different function object that takes just one parameter (the const string &). The other parameter is fixed to the value of bind1st's second argument (this).
Alternatively, if you can make FindLogDirectoryPredicate static then there's no longer any need to specify which instance to call it on, so the problem will automatically go away.
Make the predicate static
class Logger
{
public:
static bool FindLogDirectoryPredicate(const string &str);
}
Or perhaps, use a lambda.
result = std::find_if(begin(), end(), [&this] (const std::string& s)
{ return FindLogDirectoryPredicate(s); } );
You can also use a std::mem_fun (and related <functional> stuff) if you must use C++98/C++03
result = std::find_if(begin(), end(),
std::bind1st(std::mem_fun(&Logger::FindLogDirectoryPredicate), this) );
Make your predicate a static class member.
static bool FindLogDirectoryPredicate(const string &str);

Trying to pass a pointer as a parameter to a member of fstream that points to a file

/* Thanks to anyone looking at this who might attempt to answer it. I'm really not trying to waste anyone's time here, but I have beat my head on this for about three days. I realize it is probably very simple for someone who understands it. I have tried most every possible combination I can think of and still get compiler errors.
C:\random\RNDNUMTEST.cpp(41) : error C2102: '&' requires l-value
I am trying to pass a pointer as a parameter to a function makeRndmNumber() for the member function fstream.open(). I want to open the file in RNDNUMTEST.cpp and then pass it to makeRndmNumber() so that it can be modified in some way. I have looked online for help, including this website, but I feel like I am overlooking something important or simple or maybe I am just missing the concept altogether.
This isn't for homework, I'm not a college student. Although I did go to school for it, it has been over 10 years since I've done any programming and I never really understood this that well to begin with. Any suggestions would be appreciated.
// These are only excerpts from the actual files.
// RndmNum_Class.h file
typedef void(fstream::*fStream_MPT)(const char*); // fStream_MPT (Member Pointer Type)
class RandomNumber {
public:
RandomNumber();
~RandomNumber() {};
static void loadDigits(double, double, char array[]);
static int getLastNDigits(char array[], int);
static int makeRndmNumber(int, int, fStream_MPT);
};
//*************************************************************8
//RndmNum_Class.cpp file
int RandomNumber::makeRndmNumber(int seed, int _fileSize, fStream_MPT FILE) {
......
}
//**************************************************************/
// RNDNUMTEST.cpp file
#include "RndmNum_Class.h"
int main() {
const char* RNDM_FILE = "c:\\RandomFile.txt";
fstream FStream_Obj;
// FStream_Obj.open(RNDM_FILE);
fStream_MPT FileMembPtr = &FStream_Obj.open(RNDM_FILE);
//fStream_MPT FileMembPtr = &fstream::open;
int seed = 297814;
int size = 20000;
cout << RandomNumber::makeRndmNumber(seed, size, FileMembPtr);
return 0;
}
This: &FStream_Obj.open(RNDM_FILE) is not taking the address of the function, it's trying to take the address of the return value of a call to that function. But that function returns void, hence the error message.
First, change the function definition from typedef void(fstream::*fStream_MPT)(const char*); to typedef void(fstream::*fstream_MPT)(const char*,ios_base::openmode), there is a default parameter you are forgetting.
Change the fStream_MPT FileMembPtr = &FStream_Obj.open(RNDM_FILE); to fStream_MPT FileMembPtr = &fstream::open; as per your comment, and add an additional parameter to makeRndNumber, a pointer to an fstream to operate on.
int RandomNumber::makeRndmNumber(int seed, int _fileSize, fStream_MPT FILE, fstream *file)
{
((*file).*FILE)("ExampleText",ios_base::in | ios_base::out);
}
FILE = fstream::open;
EDIT
This could also be done a little cleaner with std::function objects.
First redefine your type.
typedef std::function<void(const char*)> fStream_MPT;
Then when you assign, be sure to bind your objects.
fStream_MPT FILE = std::bind(&fstream::open,&file,std::placeholders::_1, ios_base::in | ios_base::out);
Then in your function you simply call the function
int RandomNumber::makeRndmNumber(int seed, int _fileSize, fStream_MPT FILE)
{
FILE("Example text");
}
It doesn't make any sense: member function pointers is used so you can apply different member functions somewhere without knowing which exact function is called. It is like passing the function's name around (except that the name is resolved at compile-time). It doesn't seem that this is what you want to do!
Even if you would correctly obtain the function's address (rather than trying to get the address of the result of calling open()), it wouldn't work because std::fstream::open() takes two arguments: the second argument is for the open-mode and it is defaulted to std::ios_base::in | std::ios_base::out.
I'm not quite sure what you really want to d but it seems you want to pass the file stream around. The normal way to do this is to pass a reference to a std::iostream as argument to the function. Well, actually you probably want to use a std::ifstream initially and hence pass the argument as std::istream&.