(Re)named std::pair members

Ali picture Ali · May 21, 2011 · Viewed 12.7k times · Source

Instead of writing town->first I would like to write town->name. Inline named accessors (Renaming first and second of a map iterator and Named std::pair members) are the best solutions I have found so far. My problem with named accessors is the loss of type safety: pair<int,double> may refer to struct { int index; double value; } or to struct { int population; double avg_temp; }. Can anyone propose a simple approach, perhaps something similar to traits?

I often want to return a pair or a tuple from a function and it is quite tiring to introduce a new type like struct city { string name; int zipcode; } and its ctor every time. I am thrilled to learn about boost and C++0x but I need a pure C++03 solution without boost.

Update

Re andrewdski's question: yes, a (hypothetical) syntax like pair<int=index, double=value> which would create a distinct type from pair<int=population, double=avg_temp> would meet your requirement. I do not even mind having to implement a custom pair/tuple template class ONCE and just passing a 'name traits' template argument to it approprietly when I need a new type. I have no idea how that 'name traits' would look like. Maybe it's impossible.

Answer

Ben Voigt picture Ben Voigt · May 22, 2011

I don't see how you can possibly do better than

struct city { string name; int zipcode; };

There's nothing non-essential there. You need the types of the two members, your whole question is predicated around giving names to the two members, and you want it to be a unique type.

You do know about aggregate initialization syntax, right? You don't need a constructor or destructor, the compiler-provided ones are just fine.

Example: http://ideone.com/IPCuw


Type safety requires that you introduce new types, otherwise pair<string, int> is ambiguous between (name, zipcode) and (population, temp).

In C++03, returning a new tuple requires either:

city retval = { "name", zipcode };
return retval;

or writing a convenience constructor:

city::city( std::string newName, int newZip ) : name(newName), zipcode(newZip) {}

to get

return city("name", zipcode);

With C++0x, however, you will be allowed to write

return { "name", zipcode };

and no user-defined constructor is necessary.