[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

read file, execute functions

ma740988

11/16/2008 2:20:00 AM


I'm perusing a question and curiosity got the best of me in part
because I cant solve the problem

Consider:

typedef unsigned int word_type ;
class foo {

public:
void set_mx_digits_1 ( word_type wt ) {}
void set_mx_digits_2 ( double dt ) { }
// lots more.
};

Within a file, you're given a typedef'd representation of the foo
functions and the input arguments to the functions. In other words:

// filename input_file.dat
typedef void ( foo::*set_mx_digits_1 )( word_type wt ), 15
typedef void ( foo::*set_mx_digits_2 )( double dt ), 3.6
// lots more

The goal is to read the contents of the file into an appropriate
container then invoke the member functions with the input arguments.
Now I could read the contents into a string and convert the numbers
from string to int, string to double etc, but how could one store the
typedef'd representation into a map without manual intervention ( I'm
not seeing a way to read a file and store function pointers in a
map ..to compound things the input arguments are different) is beyond
me.

Maybe I misunderstood, however, if a solution exists I'd like to see
it because I'm coming up short. Thanks in advance.


7 Answers

Erik Wikström

11/16/2008 11:48:00 AM

0

On 2008-11-16 03:19, ma740988 wrote:
> I'm perusing a question and curiosity got the best of me in part
> because I cant solve the problem
>
> Consider:
>
> typedef unsigned int word_type ;
> class foo {
>
> public:
> void set_mx_digits_1 ( word_type wt ) {}
> void set_mx_digits_2 ( double dt ) { }
> // lots more.
> };
>
> Within a file, you're given a typedef'd representation of the foo
> functions and the input arguments to the functions. In other words:
>
> // filename input_file.dat
> typedef void ( foo::*set_mx_digits_1 )( word_type wt ), 15
> typedef void ( foo::*set_mx_digits_2 )( double dt ), 3.6
> // lots more
>
> The goal is to read the contents of the file into an appropriate
> container then invoke the member functions with the input arguments.
> Now I could read the contents into a string and convert the numbers
> from string to int, string to double etc, but how could one store the
> typedef'd representation into a map without manual intervention ( I'm
> not seeing a way to read a file and store function pointers in a
> map ..to compound things the input arguments are different) is beyond
> me.

You have to create a map from the typedef (or some for of it) as a
string to a member-function pointer and then fill the map when the
program starts. Then read the line from the input-file, look it up in
the map, and use the member-function pointer to invoke the function.

What you really want is probably reflection, which is not possible in
standard C++.

--
Erik Wikström

ma740988

11/16/2008 4:47:00 PM

0

On Nov 16, 6:48 am, Erik Wikström <Erik-wikst...@telia.com> wrote:
> On 2008-11-16 03:19, ma740988 wrote:
>
>
>
> > I'm perusing a question and curiosity got the best of me in part
> > because I cant solve the problem
>
> > Consider:
>
> > typedef unsigned int word_type ;
> > class foo {
>
> > public:
> >   void set_mx_digits_1 ( word_type wt ) {}
> >   void set_mx_digits_2 ( double dt ) { }
> >   // lots more.
> > };
>
> > Within a file, you're given a typedef'd representation of the foo
> > functions and the input arguments to the functions.  In other words:
>
> >   // filename input_file.dat
> >   typedef void ( foo::*set_mx_digits_1 )( word_type wt ), 15
> >   typedef void ( foo::*set_mx_digits_2 )( double dt ), 3.6
> >   // lots more
>
> > The goal is to read the contents of the file into an appropriate
> > container then invoke the member functions with the input arguments.
> > Now I could read the contents into a string and convert the numbers
> > from string to int, string to double etc, but how could one store the
> > typedef'd representation into a map without manual intervention ( I'm
> > not seeing a way to read a file and store function pointers in a
> > map ..to compound things the input arguments are different) is beyond
> > me.
>
> You have to create a map from the typedef (or some for of it) as a
> string to a member-function pointer and then fill the map when the
> program starts. Then read the line from the input-file, look it up in
> the map, and use the member-function pointer to invoke the function.

I think I'm following you. The key is essentially a string and the
value a function pointer. Correct?
Follow on question for you. There's 60 'set_WHATEVER* (WHATEVER could
be header_word, hex_digits_1, tgt_north etc. etc. etc.)' methods with
arguments double or unsigned int (word_type). Is it possible to have
templated arguments to function pointers? If how could you provide
source illustrating this. I'd like to believe I could have a generic
function pointer inside .. say a map or some appropriate container.
That function then will call the appropriate set_WHATEVER method.


> What you really want is probably reflection, which is not possible in
> standard C++.
I see.

Erik Wikström

11/16/2008 5:16:00 PM

0

On 2008-11-16 17:47, ma740988 wrote:
> On Nov 16, 6:48 am, Erik Wikström <Erik-wikst...@telia.com> wrote:
>> On 2008-11-16 03:19, ma740988 wrote:
>>
>>
>>
>> > I'm perusing a question and curiosity got the best of me in part
>> > because I cant solve the problem
>>
>> > Consider:
>>
>> > typedef unsigned int word_type ;
>> > class foo {
>>
>> > public:
>> > void set_mx_digits_1 ( word_type wt ) {}
>> > void set_mx_digits_2 ( double dt ) { }
>> > // lots more.
>> > };
>>
>> > Within a file, you're given a typedef'd representation of the foo
>> > functions and the input arguments to the functions. In other words:
>>
>> > // filename input_file.dat
>> > typedef void ( foo::*set_mx_digits_1 )( word_type wt ), 15
>> > typedef void ( foo::*set_mx_digits_2 )( double dt ), 3.6
>> > // lots more
>>
>> > The goal is to read the contents of the file into an appropriate
>> > container then invoke the member functions with the input arguments.
>> > Now I could read the contents into a string and convert the numbers
>> > from string to int, string to double etc, but how could one store the
>> > typedef'd representation into a map without manual intervention ( I'm
>> > not seeing a way to read a file and store function pointers in a
>> > map ..to compound things the input arguments are different) is beyond
>> > me.
>>
>> You have to create a map from the typedef (or some for of it) as a
>> string to a member-function pointer and then fill the map when the
>> program starts. Then read the line from the input-file, look it up in
>> the map, and use the member-function pointer to invoke the function.
>
> I think I'm following you. The key is essentially a string and the
> value a function pointer. Correct?
> Follow on question for you. There's 60 'set_WHATEVER* (WHATEVER could
> be header_word, hex_digits_1, tgt_north etc. etc. etc.)' methods with
> arguments double or unsigned int (word_type). Is it possible to have
> templated arguments to function pointers? If how could you provide
> source illustrating this. I'd like to believe I could have a generic
> function pointer inside .. say a map or some appropriate container.
> That function then will call the appropriate set_WHATEVER method.

You can probably not have just one map, since the values in a map all
have to have the same type, so you need one map for each combination of
parameter types.

You could probably use some kind of wrapper-class which container
several function-pointers and only initialise the correct one and use
that as the value, but I'm not sure if that's a good solution.

--
Erik Wikström

Paavo Helde

11/16/2008 6:00:00 PM

0

ma740988 <ma740988@gmail.com> kirjutas:

> On Nov 16, 6:48 am, Erik Wikström <Erik-wikst...@telia.com> wrote:
>> On 2008-11-16 03:19, ma740988 wrote:
>>
>>
>>
>> > I'm perusing a question and curiosity got the best of me in part
>> > because I cant solve the problem
>>
>> > Consider:
>>
>> > typedef unsigned int word_type ;
>> > class foo {
>>
>> > public:
>> >   void set_mx_digits_1 ( word_type wt ) {}
>> >   void set_mx_digits_2 ( double dt ) { }
>> >   // lots more.
>> > };
>>
>> > Within a file, you're given a typedef'd representation of the foo
>> > functions and the input arguments to the functions.  In other words:
>>
>> >   // filename input_file.dat
>> >   typedef void ( foo::*set_mx_digits_1 )( word_type wt ), 15
>> >   typedef void ( foo::*set_mx_digits_2 )( double dt ), 3.6
>> >   // lots more
>>
>> > The goal is to read the contents of the file into an appropriate
>> > container then invoke the member functions with the input arguments.
>> > Now I could read the contents into a string and convert the numbers
>> > from string to int, string to double etc, but how could one store
the
>> > typedef'd representation into a map without manual intervention (
I'm
>> > not seeing a way to read a file and store function pointers in a
>> > map ..to compound things the input arguments are different) is
beyond
>> > me.
>>
>> You have to create a map from the typedef (or some for of it) as a
>> string to a member-function pointer and then fill the map when the
>> program starts. Then read the line from the input-file, look it up in
>> the map, and use the member-function pointer to invoke the function.
>
> I think I'm following you. The key is essentially a string and the
> value a function pointer. Correct?
> Follow on question for you. There's 60 'set_WHATEVER* (WHATEVER could
> be header_word, hex_digits_1, tgt_north etc. etc. etc.)' methods with
> arguments double or unsigned int (word_type). Is it possible to have
> templated arguments to function pointers? If how could you provide
> source illustrating this. I'd like to believe I could have a generic
> function pointer inside .. say a map or some appropriate container.
> That function then will call the appropriate set_WHATEVER method.

For calling a member function you need to have:

1) an object to call the member function on
2) information about which exact member function to call
3) parameter values to the member function

In your input_file.dat there were typedefs for the member functions,
which do not really fulfill point 2). A typedef can correspond to many
member functions with the same signature. If this ambiguity is resolved
somehow, for example by saying that the typedeffed names in the .dat
files are the actual member function names to be called, only then it
becomes possible to actually call them.

In any case, you cannot construct types (like member function pointer
types) in C++ at run-time. So you have to construct all possible variants
at compile-time and choose among them. In this light it becomes
questionable if it is feasible to use a container to store the
information, because a container can hold a single value type only. One
can of course use unions or boost::any to encapsulate this, but if the
only purpose of the container is to use it for later calling the extra
hassle is not worth it (IMO). Ypu would be better off by directly calling
the member functions by reading the file, or by storing the read strings
to call them later.

In this scenario, the calling would be something like that:

if (member_fn_name=="set_mx_digits_1") {
object.set_mx_digits1( static_cast<int>(argument1));
} else if (member_fn_name=="set_mx_digits_2")
object.set_mx_digits2( static_cast<double>(argument1));
} else ...

You see, using member function pointers does not enter the picture. In
order to use member function pointers they should be somehow stored in
binary in the .dat file, to be later read back, but such a practice would
be very fragile, to say the least. I think they could be read back
reliably only in the same instance of the application, in which case
there would not be much point to store them in an external file anyway.

I hope I have not misunderstood the problem.

Paavo



ma740988

11/17/2008 12:23:00 AM

0

> Ypu would be better off by directly calling
> the member functions by reading the file, or by storing the read strings
> to call them later.

The latter I understand, the former - "You would be better off by
directly calling the member functions by reading the file" - I'm not
following. I understanding reading and storing a string then invoking
the member functions. I'm not understanding how I could read a file
then invoke the member functions directly.
Worse case show me an example in source.

Thanks

Paavo Helde

11/17/2008 7:49:00 AM

0

ma740988 <ma740988@gmail.com> kirjutas:

>> Ypu would be better off by directly calling
>> the member functions by reading the file, or by storing the read
strings
>> to call them later.
>
> The latter I understand, the former - "You would be better off by
> directly calling the member functions by reading the file" - I'm not
> following. I understanding reading and storing a string then invoking
> the member functions. I'm not understanding how I could read a file
> then invoke the member functions directly.
> Worse case show me an example in source.

Here you are, it got a bit longer than I thought, and the parser is not
very smart, and error handling is lacking, and this most probably is not
what you want, but anyway, I figure as I already wrote this for fun, I
can as well post it. (Tested by cygwin g++ 3.4.4.)

Cheers, Paavo

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

typedef std::string::size_type indx_t;

typedef unsigned int word_type ;
class foo {

public:
void set_mx_digits_1 ( word_type wt ) {
std::cout << "set_mx_digits_1(" << wt << ") called\n";
}
void set_mx_digits_2 ( double dt ) {
std::cout << "set_mx_digits_2(" << dt << ") called\n";
}
// lots more.
};

std::string FindFuncName(const std::string& buffer) {
indx_t k = buffer.find("foo::*");
if (k==buffer.npos) return "";
k += strlen("foo::*");
k = buffer.find_first_not_of(" \t", k);
if (k==buffer.npos) return "";
indx_t l = buffer.find_first_of(" \t)", k);
if (l==buffer.npos) return "";
return buffer.substr(k, l-k);
}

std::string FindArgType(const std::string& buffer) {
indx_t k = buffer.rfind("(");
if (k==buffer.npos) return "";
++k;
k = buffer.find_first_not_of(" \t", k);
if (k==buffer.npos) return "";
indx_t l = buffer.find_first_of(" \t)", k);
if (l==buffer.npos) return "";
return buffer.substr(k, l-k);
}

std::string FindArgument(const std::string& buffer) {
indx_t k = buffer.rfind(",");
if (k==buffer.npos) return "";
++k;
k = buffer.find_first_not_of(" \t", k);
if (k==buffer.npos) return "";
return buffer.substr(k);
}


// Something to silence compiler warnings and errors on invalid
// function and argument combinations.
template<typename T> T ConvertForDigits1(T x) {return x;}
int ConvertForDigits1(double x) {/* should be never called*/ return 0;}

template<typename T> T ConvertForDigits2(T x) {return x;}



template<typename T>
void CallMemberFunc(const std::string& funcname, const std::string&
argstring, foo& myfoo) {
std::istringstream argstream(argstring);
T arg1;
if (argstream >> arg1) {
if (funcname=="set_mx_digits_1") {
myfoo.set_mx_digits_1(ConvertForDigits1(arg1));
} else if (funcname=="set_mx_digits_2") {
myfoo.set_mx_digits_2(ConvertForDigits2(arg1));
} // lots more
}
}

void ReadParseAndExecute(const std::string& filename, foo& myfoo) {
std::ifstream is(filename.c_str());
std::string buffer;
while(std::getline(is, buffer)) {

// Parse the input line
std::string funcname = FindFuncName(buffer);
std::string argstring = FindArgument(buffer);
std::string argtype = FindArgType(buffer);

// dispatch to template according to argument type
if (argtype=="word_type") {
CallMemberFunc<word_type>(funcname, argstring, myfoo);
} else if (argtype=="double") {
CallMemberFunc<double>(funcname, argstring, myfoo);
} // some more
}
}

int main() {

{
// Prepare an example file
std::ofstream os("input_file.dat");
os <<
"typedef void ( foo::*set_mx_digits_1 )( word_type wt ), 15\n";
os <<
"typedef void ( foo::*set_mx_digits_2 )( double dt ), 3.6\n";
}


foo myfoo;
ReadParseAndExecute("input_file.dat", myfoo);
}

ma740988

11/17/2008 12:59:00 PM

0


> int main() {
>
>         {
>                 // Prepare an example file
>                 std::ofstream os("input_file.dat");
>                 os <<
>            "typedef void ( foo::*set_mx_digits_1 )( word_type wt ), 15\n";
>                 os <<
>            "typedef void ( foo::*set_mx_digits_2 )( double dt ), 3.6\n";
>         }
>
>         foo myfoo;
>         ReadParseAndExecute("input_file.dat", myfoo);
>
> }

You cleared up my confusion. Thanks