On Sun, 26 Aug 2007 17:24:03 +0000, BobR wrote:
Hello Bob,
Hello Erik,
Paul Brettschneider <paul.brettschneider@yahoo.fr> wrote in message...
Hello,
I have a global static array of structs and want to access a given
element using an identifier. I don't want to use the element subscript,
because it will change if I insert elements before the element I
want to access. In assembler I would simply add a label in front
of the element, but this doesn't work in C++.
[...]
Is there a way to do this in C++ (maybe some preprocessor tricks)?
Thank you.
PS: This is my first post to usenet, so bear with me.
A std::map might be an option. Depends on how 'locked-in' you are in your
current design.
// - a loose example -
#include <iostream>
#include <string>
#include <map>
class PaulA{ public:
     const char *s;
     PaulA() : s(0){}
     PaulA( char const *ss ) : s(ss){}
     };
int main(){ using std::cout; // for NG post
     std::map<std::string, PaulA> PaulMap;
     PaulMap["a"] = PaulA("a");
     PaulMap["b"] = PaulA("because");
     PaulMap["c"] = PaulA("c");
     std::string key( "d" );
     PaulMap[key] = PaulA( key.c_str() );
     cout<<" PaulMap[\"a\"] ="<<PaulMap["a"].s<<std::endl;
     cout<<" PaulMap[\"b\"] ="<<PaulMap["b"].s<<std::endl;
     cout<<" PaulMap[\"c\"] ="<<PaulMap["c"].s<<std::endl;
     cout<<" PaulMap[key] ="<<PaulMap[key].s<<std::endl;
     std::string keys( "efgh" );
     for( size_t i(0); i < keys.size(); ++i ){
          std::string tmp( 1, keys.at(i) ); // a bit on the 'ugly' side <G>
          PaulMap[ tmp ] = PaulA( tmp.c_str() );
          } // for(i)
     for( size_t i(0); i < keys.size(); ++i ){
          std::string tmp( 1, keys.at(i) );
          cout<<" PaulMap["<<tmp<<"] ="
                    <<PaulMap[tmp].s<<std::endl;
          } // for(i)
     return 0;
     } // main()
/* -output-
 PaulMap["a"] =a
 PaulMap["b"] =because
 PaulMap["c"] =c
 PaulMap[key] =d
 PaulMap[e] =e
 PaulMap[f] =f
 PaulMap[g] =g
 PaulMap[h] =h
*/
Thanks for your ideas. I know it's a common beginner mistake to care about
performance issues that can't even be measured, but looking up an
associative array at runtime, when the association can be resolved at
compile/linktime or at programm start "feels" wrong. In this case the
lookup will be orders of magnitude faster than the operation on the
element, so it wouldn't matter.
Anyway, I think I will use your idea, but instead of string-ids I will be
using an enum and be populating an id-to-object lookup-table at program
start. Similar to this:
#include <iostream>
#include <algorithm>
#include <iterator>
class A {
public:
        int id;
        const char *s;
};
class Array {
public:
        enum Id {
                element_a = 0,
                element_b,
                element_c,
                element_last            // Must be last
        };
private:
        static A items[];
        A       *last;
        A       *id2A[element_last];
public:
        Array();
        A &operator[](Id id) { return *id2A[id]; }
        A *begin() { return items; }
        A *end() { return last; }
};
A Array::items[] = {
        { element_a,    "a" },
        { element_c,    "c" },          // Order needn't be the same
        { element_b,    "b" },          // as in enum
        { element_last, NULL }          // Must be last
};
Array::Array()
{
        A *it;
        for(it = items; it->id != element_last; ++it)
                id2A[it->id] = it;
        last = it;
}
std::ostream &operator<< (std::ostream &out, const A &a)
{
        return out << a.s;
}
static Array array;
int main()
{
        // Access all elements
        std::copy(array.begin(),
                  array.end(),
                  std::ostream_iterator<A>(std::cout, "\n"));
        // Access elements by id
        std::cout << array[Array::element_a] << '\n'
                  << array[Array::element_b] << '\n'
                  << array[Array::element_c] << std::endl;
        return 0;
}
It's too bad that C++ doesn't know C99-style designated initialisators.
IMHO it's a really nice feature which I could (mis)use like this:
// Untested - doesn't compile
#include <iostream>
#include <algorithm>
#include <iterator>
class A {
public:
        enum ids {
                element_a = 0,
                element_b,
                element_c,
                element_last                    // Must be last!
        };
        const char *s;
};
static A array[] = {
        [A::element_a] = { "a" },               // Doesn't compile!
        [A::element_c] = { "c" },
        [A::element_last] = { NULL }            // Order irrelevant
        [A::element_b] = { "b" },
};
std::ostream &operator<< (std::ostream &out, const A &a)
{
        return out << a.s;
}
int main()
{
        // Access all elements
        std::copy(&array[A::element_a],
                  &array[A::element_last],
                  std::ostream_iterator<A>(std::cout, "\n"));
        // Access all elements by id
        std::cout << &array[A::element_a] << '\n'
                  << &array[A::element_b] << '\n'
                  << &array[A::element_c] << std::endl;
        return 0;
}
Does anybody know if this is planned in a future C++-standard?
types as well.