Finding variable names at compile time

Hi
I have a class called "ItemManager" that contains a vector of "Item" structs.

The item struct contains various information about an item such as: string name, int modelID, uint16_t value, int itemID, etc..)

I would like to be able to search though the item vector.
The problem is that in order to do that i will have to make a bunch of functions like this:
Item* FindItemByName(std::string name)
and
Item* FindItemByValue(int value)
etc.. for each member of the Item struct.

But i don't like this very much since I've been taught to never repeat myself when programming and here i'm basically repeating the same piece of searching code just changing the variable name each time.

Ideally i would like something like this:
1
2
3
Item* FindItem<T>(std::string varToSearch,T valToSearchFor);

FindItem<uint16_t>("value", 103);


But there doesn't seem to be a way to achieve this since there is no variable names at runtime.

Is there some wired #define trickery that could get around this?
like somehow figure out the variable names and offsets in to the struct
and then make a std::map of the strings and offsets?
Last edited on
EDIT:
So i've found out a way to get the offsets using the offsetof macro ( which i assume isn't compiler specific? right? )

So in my Item struct im basically gonna declare a std::map<std::string names, int offsets> and populate it in the constructor like so:
1
2
3
map["name"] = (int)offsetof(struct Item, name);
map["modelID"] = (int)offsetof(strict Item, modelID);
..etc..


Is this an ok solution? or is it bad in some way?

I'm open to suggestions to better ways of doing this
Last edited on
A couple of questions.

First are the search fields unique or can there be duplicates?

Second have you considered something like std::find_if() using a custom "pred" for each different search field (possibly by using a lambda).
http://www.cplusplus.com/reference/algorithm/find_if/





Something along these lines, perhaps:

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 <string>
#include <tuple>
#include <vector>

struct item : std::tuple< std::string, int, int >
{
    using std::tuple< std::string, int, int >::tuple ;

    std::string name() const { return std::get<std::string>(*this) ; }
    int id() const { return std::get<1>(*this) ; }
    int value() const { return std::get<2>(*this) ; }

    enum member { NAME, ID, VALUE }; // *** caveat: somewhat brittle
                                     // needs to be updated if a new member is added
    template < member m > decltype(auto) get() const { return std::get<m>(*this) ; }
};

template < item::member m, typename ITEM_SEQ, typename T >
auto find( ITEM_SEQ& seq, const T& value )
{
    for( auto& x : seq ) if( x.template get<m>() == value ) return std::addressof(x) ;
    return decltype( std::addressof( *std::begin(seq) ) ){} ;
}

int main()
{
    std::vector<item> items { { "one", 1, 1 }, { "two", 2, 20 }, { "three", 3, 30 } } ;

    auto ptr = find<item::NAME>( items, "two" ) ;
    if(ptr) std::cout << ptr->name() << '\n' ; // two

    ptr = find<item::VALUE>( items, 30 ) ;
    if(ptr) std::cout << ptr->name() << '\n' ; // three

    ptr = find<item::ID>( items, 37 ) ;
    if(ptr) std::cout << ptr->name() << '\n' ;
    else std::cout << "not found\n" ; // not found
}

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