changing a variable value according to it's name

Jan 17, 2014 at 1:07pm
hello,

I was wondering if there is a way to change a certain variable's value if I know it's name?

For example,say you have a struct called 'profile' who has sveral variable in it: id, address, height, weight, and so on. Assume all variable have default values and the value of 'height' is 60. Now let say someone gave you a string as an input:"height=80". What I want to do is to be able to read to input, parse it and change the value to 'height' to 80. The first two parts I can do (read and parse), what I don't know is how the change the value.

Any advice? I would appreciate it if you could add a code sample.


P.S. working with cpp
Last edited on Jan 17, 2014 at 2:18pm
Jan 17, 2014 at 1:48pm
No. The variable names are just there to help you as a programmer make sense of the program. After the code has been compiled the variable names are of no importance.

You probably could use a map (std::map or std::unordered_map) instead.
http://en.cppreference.com/w/cpp/container/map
http://en.cppreference.com/w/cpp/container/unordered_map
Jan 17, 2014 at 2:08pm
In other words, the 'profile' should have a method, which takes input, and acts as necessary.
input := "height=80 foo=bar"
tokenize
=>
token0 := "height"
value0 := "80"
token1 := "foo"
value1 := "bar"

for each token:
IF "height" == token
THEN
  IF value is an integer
  THEN this->height := toInt(value)
  ENDIF
ELSE IF ...

And yes, a map could be used to implement the IF .. ELSE IF ...


Boost has code to parse command line parameters into option variables.
Qt has "meta object" properties.
Jan 17, 2014 at 2:09pm
I tought about using a map but I don't know how to do it in case of a struct.

Would be glad to see some code sample in c++
Last edited on Jan 17, 2014 at 2:17pm
Jan 17, 2014 at 2:41pm
> Would be glad to see some code sample in c++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <map>
#include <string>
#include <functional>

struct profile
{
    void set( std::string name, std::string value )
    {
        auto iter = setters.find(name) ;
        if( iter != setters.end() ) iter->second( this, value ) ;
    }

    std::string id = "none" ;
    int height = 0 ;
    // etc.

    using setter_type = std::function< void( profile*,  std::string ) > ;
    static const std::map< std::string, setter_type > setters ;
};

const std::map< std::string, profile::setter_type > profile::setters
{
    { "id", []( profile* This, std::string value ) { This->id = value ; } },
    { "height", []( profile* This, std::string value ) { This->height = std::stoi(value) ; } }
    // etc.
};

int main()
{
    profile p ;
    std::cout << "id: " << p.id << "   height: " << p.height << '\n' ;
    
    p.set( "id", "this is a local profile" ) ;
    std::cout << "id: " << p.id << "   height: " << p.height << '\n' ;

    p.set( "height", "3456789" ) ;
    std::cout << "id: " << p.id << "   height: " << p.height << '\n' ;
}

http://coliru.stacked-crooked.com/a/4ac217c3ab2aa1b6
Jan 20, 2014 at 11:42am
Hi,

First, thanks for the help and for the code.
Second, from some reason, when I try to run your code I'm getting errors:
'personal:: id' : only static const integral data members can be initialized within a class
'Setter_type' : symbol cannot be used in a using declartion
//Etc

I managed to get rid of the first one by not initialzing it.

I couldn't get rid from the second. I tried to change it to:
Typedef std::function<void(persona*, std::string)> setter_type;
But now I get: error c2039: 'function' : is not a member of 'std'

Any advice?
Last edited on Jan 20, 2014 at 12:05pm
Jan 20, 2014 at 12:03pm
C++11. Your compiler did not have the support for C++11 enabled.
Jan 20, 2014 at 2:13pm
> Any advice?

Well, switch to a more modern compiler; Visual C++ 12.0 which ships with Visual Studio 2013 is a good option.

Otherwise, we would have to restrict our code so that it conforms to C++98.

Try this on your current compiler; unless it is ancient, this would compile cleanly:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <map>
#include <string>
#include <cstdlib> // std::strtol

// we wouldn't have std::stoi, so we will write a function
int string_to_int( std::string str ) // error checks elided
{ return std::strtol( str.c_str(), 0, 10 ) ; }

struct profile
{
    // the setter_type is now a pointer to member function
    typedef void (profile::*setter_type)( std::string ) ;

    void set( std::string name, std::string value )
    {
        std::map< std::string, setter_type >::const_iterator iter = setters.find(name) ;
        if( iter != setters.end() )
        {
            setter_type pfn = iter->second ; // get the pointer to member function
            ( this->*pfn )(value) ; // and call it with value as the argument
        }
    }

    // a constructor to initialize members
    profile() : id("none"), height(0), width(0) {}

    std::string id ;
    int height ;
    int width ;
    // etc.

    // member functions to set the values
    void set_id( std::string str_id ) { id = str_id ; }
    void set_height( std::string str_height ) { height = string_to_int(str_height) ; }
    void set_width( std::string str_width ) { width = string_to_int(str_width) ; }
    // etc.

    static std::map< std::string, setter_type > setters ;
    static bool init_helper() ;
    static const bool init ;
};

std::map< std::string, profile::setter_type > profile::setters ;

// helper function to populate the map
bool profile::init_helper()
{
    setters["id"] = &profile::set_id ;
    setters["height"] = &profile::set_height ;
    setters["width"] = &profile::set_width ;
    // etc.
    return true ;
}

const bool profile::init = init_helper() ; // populates map by calling init_helper()

std::ostream& operator<< ( std::ostream& stm, const profile& p )
{
    return stm << "profile { id:" << p.id << ", height:" << p.height
                << ", width:" << p.width << " }" ;
}

int main()
{
    profile p ;
    std::cout << p << '\n' ;

    p.set( "id", "local" ) ;
    std::cout << p << '\n' ;

    p.set( "height", "3456" ) ;
    std::cout << p << '\n' ;

    p.set( "width", "999" ) ;
    std::cout << p << '\n' ;
}

http://coliru.stacked-crooked.com/a/e225a9b2c7e0ef84
Topic archived. No new replies allowed.