2

Right now I have a switch statement that takes in an input and choose one of the following actions:

Option 1

for(; i < queue_size; ++i)
{
   prepared->setString(i+1, queue.at(i).model);
}

Option 2

for(; i < queue_size; ++i)
{
   prepared->setString(i+1, queue.at(i).manufacturer);
}

Option 3

for(; i < queue_size; ++i)
{
   prepared->setString(i+1, queue.at(i).name);
}

In PHP, you would be able to do the same doing something like this:

$queue[i][$member];

$member could then be set to "name", "manufacturer", etc.

Is there any way to do something similar or more robust in C++?

Thanks in advance for any help/suggestions!

noko
  • 1,129
  • 2
  • 14
  • 25

6 Answers6

4

Using C++11 std::function or boost::function if you don't have C++11:

std::map<YourSwitchType, std::function<void(void)> functionMap;

then define functions such as

void manufacturString() {
  for(; i < queue_size; ++i) {
    prepared->setString(i+1, queue.at(i).manufacturer);
  }
}

for each case, and populate the map with these.

functionMap[someSwitchValue] = std::bind(&ThisType::manufactureString, this);

Then you can just call them:

functionMap[someSwitchValue]();

One advantage of this approach is that it doesn't limit you to member functions. You can put non-member functions, functors, static member and non-member functions in the same map. The only limitation is that after binding, they return void and take no arguments (that is specific to this example).

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
3

You could do this with a map from your property names to pointer-to-member. But it's a bit of work (you need to create that mapping yourself), and the syntax gets a bit hairy. (And all the members you want to address this way must be of the same type.)

Demo:

#include <iostream>
#include <map>

struct Foo {
    std::string name;
    std::string address;
};

typedef std::string Foo::* FooMemPtr;
typedef std::map<std::string, FooMemPtr> propmap;

int main()
{
    propmap props;
    props["name"] = &Foo::name;
    props["address"] = &Foo::address;

    /* ... */

    Foo myfoo;
    myfoo.*(props["name"]) = "myname";
    myfoo.*(props["address"]) = "myaddress";
    std::cout << myfoo.*(props["address"]) << std::endl;
    std::cout << myfoo.*(props["name"]) << std::endl;
}
Mat
  • 202,337
  • 40
  • 393
  • 406
  • Forgot to mention that all the members must be of the same type. Edited that in, it's a pretty severe limitation. – Mat May 18 '12 at 08:14
1

If you can use enums instead of strings, then you can access name, manufacturer, etc. indexed off of the enum values. It depends on how dynamic you need to be.

Yusuf X
  • 14,513
  • 5
  • 35
  • 47
0

Use the STL map to perform this. It works as you would do in PHP.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • -1 for calling it STL and linking to cplusplus.com. http://programmers.stackexchange.com/questions/88241/whats-wrong-with-cplusplus-com, http://stackoverflow.com/questions/5205491/whats-this-stl-vs-c-standard-library-fight-all-about/5205571#5205571 – Griwes May 18 '12 at 08:13
  • @juanchopanza, probably, but telling inexperienced people to google for "std " leads them to cplusplus.com, which is... well, wrong - unless you have some experience and know how to use cplusplus.com and know where it is wrong. – Griwes May 18 '12 at 08:23
  • I understand that someone doesn't like to be corrected and tries to fight back, but you could've chosen answers that were actually wrong, not those that were correct :D I will remove downvote as soon as you remove "STL" and cplusplus.com references from your answer; downvoting mine answers (that were correct) seems a bit childish. – Griwes May 18 '12 at 08:25
  • I know that some bits of that web site are wrong. But I find that overall it is not too bad. In my experience all web sites have mistakes. Perhaps you could write a perfect web site for C++ instead of critising. – Ed Heal May 18 '12 at 08:25
  • @EdHeal, have you looked at links I've provided? If so, you know that there exists site that is much more perfect than cplusplus.com: cppreference. – Griwes May 18 '12 at 09:32
  • @Griwes - I know of that web site. Just prefer to use both. I am not going to change my post regardless of you down vote - that I thought was rather harsh and unjustified. – Ed Heal May 18 '12 at 09:59
  • @EdHeal, it's not just my opinion, as you can see looking at links I provided. I've no problem with you using both of them; I have problem with you providing (potential) language newcomers with link to cplusplus.com, which introduces wrong programming styles. I don't care if you understand what I wrote; if not, don't even spam my notifications with another comment. – Griwes May 18 '12 at 10:31
  • @Griwes - Tough - Other people like the other web site. Not just me. I am not going to further comment on you utterances. I have my opinion - you have yours. – Ed Heal May 18 '12 at 10:35
0

One option is to pass an extractor functor to the function:

#include <string>
#include <vector>
#include <boost/bind.hpp>

struct Some {
    std::string model, manufacturer, name;
};

struct Prepared {
    void setString(size_t, std::string const&);
};

template<class Extractor>
void foo(Extractor extract) {
    Prepared* prepared = 0;
    std::vector<Some> queue;
    size_t i, queue_size = queue.size();
    for(; i < queue_size; ++i) {
        prepared->setString(i+1, extract(queue.at(i)));
    }
}

int main() {
    // C++03
    foo(boost::bind(&Some::model, _1));
    foo(boost::bind(&Some::manufacturer, _1));
    foo(boost::bind(&Some::name, _1));

    // C++11
    foo([](Some const& some){ return some.model; });
    foo([](Some const& some){ return some.manufacturer; });
    foo([](Some const& some){ return some.name; });
}
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
0

You can do this type of thing using member variable points (there are also member function pointers). The boost bind functions are more generic, but this is ultimately what they are doing underneath (at least in this scenario).

#include <iostream>
#include <string>

struct item
{
    std::string a, b;
};

//the really ugly syntax for a pointer-to-member-variable
typedef std::string item::*mem_str;

//show each member variable from the list
void show_test( item * objs, size_t len, mem_str var )
{
    for( size_t i=0; i < len; ++i )
        std::cout << objs[i].*var << std::endl;
}

int main()
{
    //create some test data
    item test[2];
    test[0].a = "A-Zero";
    test[0].b = "B-Zero";

    test[1].a = "A-One";
    test[1].b = "B-One";

    //show variables
    show_test( test, 2, &item::a );
    show_test( test, 2, &item::b );

    return 0;
}
edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267