Home

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?

previous
next

Re: Latest models of Gibson guitars
Re: Python is removing my quotes!
Re: C++: integer constant is too large for "long" type
Re: about __str__
Re: inline function
Dzieci Niczyje
Fundacja Hobbit
Mam Marzenie
Podaruj Zycie
Rodzic Po Ludzku