Adding Map Entries

C

cppaddict

Hi,

I have some code which uses std::map to associate cartesian POINTs
with values. My current syntax for adding new (POINT,value) entries
to the map is clunky -- it takes three lines for each entry. There
must be a way to trim it down:

<code>
#include <map>
#include <iostream>

typedef struct tagPOINT { // pt
long x;
long y;
} POINT;

//map comparison fctn
struct PointCompare {
bool operator() (POINT p1, POINT p2) const {
if (p1.x == p2.x)
return p1.y < p2.y;
else
return p1.x < p2.x;
}
};


int main() {


std::map<POINT, int,PointCompare> testPoints;

//THIS CODE IS HERE IS THE PROBLEM
POINT pnt1 = {1,1};
std::pair<POINT, int> pair1(pnt1,123);
testPoints.insert(pair1);

POINT pnt2 = {1,2};
std::pair<POINT, int> pair2(pnt2,456);
testPoints.insert(pair2);

std::cout << "direct access {1,1} -> " << testPoints[pnt1] <<
std::endl;

std::map<POINT, int, PointCompare>::iterator iter;
for (iter = testPoints.begin(); iter != testPoints.end();
++iter) {
POINT iterPnt = iter->first;
std::cout << "iterator access: iter->first = {" <<
iterPnt.x << "," << iterPnt.y << "}" << std::endl;
std::cout << "iterator access: iter->second = " <<
(iter->second) << std::endl;
}

return 0;
}

</code>

Thanks for any help,
cpp
 
D

Dave Townsend

You can make things a bit simpler by making POINTs real objects
and adding a constructor so you can stamp out POINT objects
like POINT p(1,2) instead of the mechanism you are using.

You dont have to explicitly create variables for POINT and pair,
you can do things like this:
testPoints.insert( std::pair<POINT,int>(POINT(1,2), 456) );

this creates a temporary POINT object with values 1, 2 and a pair
object with that POINT and they int value 456.

The std::pair<POINT,int> is a bit of a mouthful, I thought you
could just do std::pair and the compiler should deduce the template
arguments, however you can just create a typedef to use instead if
you don't want to type that stuff in over and over.

I've tinkered with your original code below

#include <std_disclaimers.h>

#include <map>
#include <iostream>
struct POINT { // pt
long x;
long y;
POINT(long xx, long yy)
:x(xx), y(yy){}
} ;

//map comparison fctn
struct PointCompare {
bool operator() (POINT p1, POINT p2) const {
if (p1.x == p2.x)
return p1.y < p2.y;
else
return p1.x < p2.x;
}
};


int main() {


std::map<POINT, int,PointCompare> testPoints;





POINT pnt2(1,2);

testPoints.insert( std::pair<POINT,int>(POINT(1,2), 456) );
POINT pnt1(1,2);
std::cout << "direct access {1,1} -> " << testPoints[pnt1] <<
std::endl;

std::map<POINT, int, PointCompare>::iterator iter;
for (iter = testPoints.begin(); iter != testPoints.end();
++iter) {
POINT iterPnt = iter->first;
std::cout << "iterator access: iter->first = {" <<
iterPnt.x << "," << iterPnt.y << "}" << std::endl;
std::cout << "iterator access: iter->second = " <<
(iter->second) << std::endl;
}

return 0;
}





cppaddict said:
Hi,

I have some code which uses std::map to associate cartesian POINTs
with values. My current syntax for adding new (POINT,value) entries
to the map is clunky -- it takes three lines for each entry. There
must be a way to trim it down:

<code>
#include <map>
#include <iostream>

typedef struct tagPOINT { // pt
long x;
long y;
} POINT;

//map comparison fctn
struct PointCompare {
bool operator() (POINT p1, POINT p2) const {
if (p1.x == p2.x)
return p1.y < p2.y;
else
return p1.x < p2.x;
}
};


int main() {


std::map<POINT, int,PointCompare> testPoints;

//THIS CODE IS HERE IS THE PROBLEM
POINT pnt1 = {1,1};
std::pair<POINT, int> pair1(pnt1,123);
testPoints.insert(pair1);

POINT pnt2 = {1,2};
std::pair<POINT, int> pair2(pnt2,456);
testPoints.insert(pair2);

std::cout << "direct access {1,1} -> " << testPoints[pnt1] <<
std::endl;

std::map<POINT, int, PointCompare>::iterator iter;
for (iter = testPoints.begin(); iter != testPoints.end();
++iter) {
POINT iterPnt = iter->first;
std::cout << "iterator access: iter->first = {" <<
iterPnt.x << "," << iterPnt.y << "}" << std::endl;
std::cout << "iterator access: iter->second = " <<
(iter->second) << std::endl;
}

return 0;
}

</code>

Thanks for any help,
cpp
 
A

Ali Cehreli

Hi,

I have some code which uses std::map to associate cartesian POINTs with
values. My current syntax for adding new (POINT,value) entries to the
map is clunky -- it takes three lines for each entry. There must be a
way to trim it down:

<code>
#include <map>
#include <iostream>

typedef struct tagPOINT { // pt
long x;
long y;
} POINT;

You don't need the typedef trick for struct declarations in C++:

struct tagPOINT { /* ... */ };
or
struct POINT { /* ... */ };

It is convenient to define a constructor even for a simple struct so
that the code will be more readable (see below):

struct POINT
{
long x;
long y;

POINT(long x_arg, long y_arg)
:
x(x_arg),
y(y_arg)
{}
};

[...]
int main() {


std::map<POINT, int,PointCompare> testPoints;

You can use typedefs to simplify the code:

typedef std::map<POINT, int,PointCompare> Points;
typedef Points::iterator PointIter;

Points testPoints;
//THIS CODE IS HERE IS THE PROBLEM
POINT pnt1 = {1,1};
std::pair<POINT, int> pair1(pnt1,123);
testPoints.insert(pair1);

Now you can replace the above three lines with

testPoints.insert(std::make_pair(POINT(1, 1), 123));

Alternatively:

testPoints[POINT(1, 1)] = 123;

[...]
std::map<POINT, int, PointCompare>::iterator iter;
for (iter = testPoints.begin(); iter != testPoints.end(); ++iter)

The typedef defined above will make this simpler too:

for (PointIter iter = /* ... */)

Ali
 
A

Ali Cehreli

The std::pair<POINT,int> is a bit of a mouthful, I thought you could
just do std::pair and the compiler should deduce the template arguments,

Argument deduction works only for function templates; not class
templates.

Some template classes have a corresponding function template to do the
argument deduction. For example:

template <class A>
class Foo
{
public:
Foo(A const & a);
/* ... */
};

template <class A>
Foo<A> MakeFoo(A const & a)
{
return Foo<A>(a);
}

The convenience function for std::pair is std::make_pair.

Ali
 
J

Jerry Coffin

cppaddict said:
Hi,

I have some code which uses std::map to associate cartesian POINTs
with values. My current syntax for adding new (POINT,value) entries
to the map is clunky -- it takes three lines for each entry. There
must be a way to trim it down:

There is. Some other parts can be a bit neater as well:

#include <map>
#include <iostream>
#include <iterator>
#include <algorithm>

class POINT {
long x;
long y;

friend std::eek:stream &operator<<(std::eek:stream &os, POINT const &p) {
return os << "{" << p.x << "," << p.y << "}";
}
public:
bool operator<(POINT const &p2) const {
if (x == p2.x)
return y < p2.y;
else
return x < p2.x;
}

POINT(long x_init, long y_init) : x(x_init), y(y_init) {}
};

typedef std::pair<POINT, int> pp;

std::eek:stream &operator<<(std::eek:stream &os, pp const &p) {
return os << "point " << p.first << " -> " << p.second;
}

int main() {
std::map<POINT, int> testPoints;

testPoints[POINT(1,1)] = 123;
testPoints[POINT(1,2)] = 456;

std::cout << "point {1,1} -> " << testPoints[POINT(1,1)]
<< " (direct access)\n";
std::copy(testPoints.begin(), testPoints.end(),
std::eek:stream_iterator<pp>(std::cout, " (algorithm)\n"));

return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top