Initializing std::map Objects

M

Mike Copeland

I have the following structure and declarations, and I'm looking for
any simple way to initialize a set of default values.

struct TSINFO
{
string tsDescr; // T-Shirt name
string tsValue; // source T-Shirt value
char tsCode; // T-Shirt code (cShirt)
char tsGender; // T-Shirt gender version
int tsCount; // count of T-Shirts of this type
} extern tsWork;
typedef map<char, TSINFO> shirtLUMap;
shirtLUMap tsLUMap;
shirtLUMap::iterator tsluIter; // lookup iterator

That is, I wish to create, say, 5 objects with specific values and
store them into the map. For example,
tsWork.tsCode = 'S';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Small";
shirtLUMap['S'] = tsWork;
tsWork.tsCode = 'M';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Medium";
shirtLUMap['M'] = tsWork;
tsWork.tsCode = 'A';
tsWork.tsGender = 'F';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Female X-Small";
shirtLUMap['A'] = tsWork;
[etc.]

Such code is tedious, and I'd like to learn some way to "shorthand"
the process of declaring certain default values. Using a non-default
constructor seems useful, but I don't know how I'd do it here... Please
advise.. TIA
 
D

David FLEURY

Le 23/06/2013 19:57, Mike Copeland a écrit :
Such code is tedious, and I'd like to learn some way to "shorthand"
the process of declaring certain default values. Using a non-default
constructor seems useful, but I don't know how I'd do it here... Please
advise.. TIA

May be using a FactoryMethod with some params that returns a TSINFO?

TSINFO CreateTSINFO( <some params> )
{
TSINFO tmp;
<some init like tmp.tsCount = 0>
return tmp;
}

TSINFO tsInfo = CreateTSINFO(...)
shirtLUMap[tsInfo.tsCode] = tsInfo;
 
I

Ian Collins

Mike said:
I have the following structure and declarations, and I'm looking for
any simple way to initialize a set of default values.

struct TSINFO

Many (most?) coding standards reserve all caps names for macros.
{
string tsDescr; // T-Shirt name
string tsValue; // source T-Shirt value
char tsCode; // T-Shirt code (cShirt)
char tsGender; // T-Shirt gender version
int tsCount; // count of T-Shirts of this type
} extern tsWork;
typedef map<char, TSINFO> shirtLUMap;
shirtLUMap tsLUMap;
shirtLUMap::iterator tsluIter; // lookup iterator

That is, I wish to create, say, 5 objects with specific values and
store them into the map. For example,
tsWork.tsCode = 'S';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Small";
shirtLUMap['S'] = tsWork;

Why don't you add a constructor with default values to your struct?
 
S

SG

Am 23.06.2013 19:57, schrieb Mike Copeland:
I have the following structure and declarations, and I'm looking for
any simple way to initialize a set of default values.

struct TSINFO
{
string tsDescr; // T-Shirt name
string tsValue; // source T-Shirt value
char tsCode; // T-Shirt code (cShirt)
char tsGender; // T-Shirt gender version
int tsCount; // count of T-Shirts of this type
} extern tsWork;
typedef map<char, TSINFO> shirtLUMap;
shirtLUMap tsLUMap;
shirtLUMap::iterator tsluIter; // lookup iterator

That is, I wish to create, say, 5 objects with specific values and
store them into the map. For example,
tsWork.tsCode = 'S';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Small";
shirtLUMap['S'] = tsWork;
tsWork.tsCode = 'M';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Medium";
shirtLUMap['M'] = tsWork;
tsWork.tsCode = 'A';
tsWork.tsGender = 'F';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Female X-Small";
shirtLUMap['A'] = tsWork;
[etc.]

Such code is tedious, and I'd like to learn some way to "shorthand"
the process of declaring certain default values. Using a non-default
constructor seems useful, but I don't know how I'd do it here... Please
advise.. TIA

Try this:

shirtLUMap tsLUMap = {
{'S', {"Small" ,"",'S','U',0}},
{'M', {"Medium","",'M','U',0}},
{'A', {"Female X-Small","",'A','F',0}}
};

in C++11 mode (untested).

But I also liked David's suggestion. You could even ged rid of the named
TSINFO object in his example by writing

addEntry(tsLUMap,...params...);
addEntry(tsLUMap,...params...);
addEntry(tsLUMap,...params...);

where

void addEntry(shirtLUMap & map, ...params...);
{
TSINFO & tsi = map[tsCode];
tsi.tsCode = tsCode;
tsi.more = more;
...
}

But maybe you should rethink the whole data structure. It does not look
like a smart choice if you want to use it as a database for all
available T-Shirts.
 
C

Christopher Pisz

I have the following structure and declarations, and I'm looking for
any simple way to initialize a set of default values.

struct TSINFO
{
string tsDescr; // T-Shirt name
string tsValue; // source T-Shirt value
char tsCode; // T-Shirt code (cShirt)
char tsGender; // T-Shirt gender version
int tsCount; // count of T-Shirts of this type
} extern tsWork;
typedef map<char, TSINFO> shirtLUMap;
shirtLUMap tsLUMap;
shirtLUMap::iterator tsluIter; // lookup iterator

That is, I wish to create, say, 5 objects with specific values and
store them into the map. For example,
tsWork.tsCode = 'S';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Small";
shirtLUMap['S'] = tsWork;
tsWork.tsCode = 'M';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Medium";
shirtLUMap['M'] = tsWork;
tsWork.tsCode = 'A';
tsWork.tsGender = 'F';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Female X-Small";
shirtLUMap['A'] = tsWork;
[etc.]

Such code is tedious, and I'd like to learn some way to "shorthand"
the process of declaring certain default values. Using a non-default
constructor seems useful, but I don't know how I'd do it here... Please
advise.. TIA

Wow that is an ugly struct! It is so C! Don't you think the data can be
better represented than with strings and characters?

When someone debugs through the code, do they need a lucky charms
encoder/decoder ring? What is 'U' ? What is 'S'? What is 'A'?

What does "value?" represent? Even with the comment, it could be
anything. What does "code" represent? The comment is no help.

code // Code doesn't tell anyone anything about what code represents.

I hate having to debug code like that with some data that could be anything.

sorry to be picky, but I have to work with a peer that does this and it
makes my life hell.

What is the character in the map that is serving as the key?

This would be much more C++ IMO if you made some enums to represent
possible values and a class whose member data consisted of this enums.
It would also be faster code.

enum TShirtGender
{
TSHIRT_GENDER_UNKNOWN = -1,
TSHIRT_GENDER_MALE,
TSHIRT_GENDER_FEMALE,
TSHIRT_GENDER_NUETRAL
};

class TShirt
{
public:

TShirt();
TShirt(const TShirtGender gender = TSHIRT_GENDER_UNKNOWN);
TShirt(const TShirt & rhs);
~TShirt();

TShirt & operator = (const TShirt & rhs);

const TShirtGender GetGender() const;
void SetGender(const TShirtGender);

private:

TShirtGender m_gender;
};

Add other data members as appropriate.
 
C

Christopher Pisz

enum TShirtGender
{
TSHIRT_GENDER_UNKNOWN = -1,
TSHIRT_GENDER_MALE,
TSHIRT_GENDER_FEMALE,
TSHIRT_GENDER_NUETRAL
};

class TShirt
{
public:

TShirt();
TShirt(const TShirtGender gender = TSHIRT_GENDER_UNKNOWN);
TShirt(const TShirt & rhs);
~TShirt();

TShirt & operator = (const TShirt & rhs);

const TShirtGender GetGender() const;
void SetGender(const TShirtGender);

private:

TShirtGender m_gender;
};

Add other data members as appropriate.


Alternatively, you can do this as well

struct TShirt
{
public:

enum Gender
{
TSHIRT_GENDER_UNKNOWN = -1,
TSHIRT_GENDER_MALE,
TSHIRT_GENDER_FEMALE,
TSHIRT_GENDER_NUETRAL
};

TShirt();
TShirt(const TShirtGender gender = TSHIRT_GENDER_UNKNOWN);
TShirt(const TShirt & rhs);
~TShirt();

TShirt & operator = (const TShirt & rhs);

unsigned long m_id; // Unique ID
TShirtGender m_gender;
};

Since get and set aren't really going to do anything special and the
enum is only going to be used with the class.

// Key - TShirt ID
// Value - Count in stock
std::map<unsigned long, unsigned long> inventory;

I don't think count was really past of a TShirt...it can be represented
in an inventory outside of the class, but one cannot tell what the
original struct was being used for with only "info" to go on.
 
S

SG

Am 24.06.2013 17:33, schrieb Christopher Pisz:
Alternatively, you can do this as well

struct TShirt
{
public:

enum Gender
{
TSHIRT_GENDER_UNKNOWN = -1,
TSHIRT_GENDER_MALE,
TSHIRT_GENDER_FEMALE,
TSHIRT_GENDER_NUETRAL
};

TShirt();
TShirt(const TShirtGender gender = TSHIRT_GENDER_UNKNOWN);
TShirt(const TShirt & rhs);
~TShirt();

TShirt & operator = (const TShirt & rhs);

unsigned long m_id; // Unique ID
TShirtGender m_gender;
};

Do copy ctor and assignment operator and dtor serve a special purpose or
do you just like declaring things the compiler would have generated
automatically? :) Maybe it has something to do with "m_id" which is
supposed to be unique. But then again, why putting an m_id in there?

Cheers!
SG
 
C

Christopher Pisz

Am 24.06.2013 17:33, schrieb Christopher Pisz:

Do copy ctor and assignment operator and dtor serve a special purpose or
do you just like declaring things the compiler would have generated
automatically? :) Maybe it has something to do with "m_id" which is
supposed to be unique. But then again, why putting an m_id in there?

Cheers!
SG

Well, the OP was wanting to handle default initialization and insert
into a std::map in his code, so one would need to provide a copy
constructor. I find it best practice to include a destructor, if for no
other reason, then to provide a point to break on when debugging.
Assignment operator would prove useful for a class like this, but like I
said, there is no contextual information given. If I had an Order that
took a Tshirt, I _might_ assign a specific TShirt to that order.

The id field was for the inventory. Understand, this was all under the
clause of "alternatively". I want to show the OP what options there are
for accomplishing different things, when assumedly, he is coming from a
place where he cannot make a constructor work with default arguments.
 
B

Bart van Ingen Schenau

Well, the OP was wanting to handle default initialization and insert
into a std::map in his code, so one would need to provide a copy
constructor.

The class needs a copy-constructor, but you, as programmer, don't
necessarily have to write it.
If you, the programmer, don't declare a copy-constructor, the compiler
will create one for you, if it is needed, which performs a member-wise
copy of all of the members of the class. If the copy-constructor you
would have written does exactly the same, then why bother spending the
time on it?
I find it best practice to include a destructor, if for no
other reason, then to provide a point to break on when debugging.

That's a fair reason.
Assignment operator would prove useful for a class like this, but like I
said, there is no contextual information given. If I had an Order that
took a Tshirt, I _might_ assign a specific TShirt to that order.

(Copy-)assignment is also one of those special members that the compiler
can create for you.

Bart v Ingen Schenau
 
J

James Kanze

Am 23.06.2013 19:57, schrieb Mike Copeland:

Just a nit, but IIRC, C has deprecated putting the storage class
anywhere but as the first token in the declaration. This would
be a lot cleaner if you defined the class first, then declared
the variable. (But why do you need the variable to begin with?)

And as Ian pointed out, class names really shouldn't be all
caps.
typedef map<char, TSINFO> shirtLUMap;
shirtLUMap tsLUMap;
shirtLUMap::iterator tsluIter; // lookup iterator
That is, I wish to create, say, 5 objects with specific values and
store them into the map. For example,
tsWork.tsCode = 'S';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Small";
shirtLUMap['S'] = tsWork;
tsWork.tsCode = 'M';
tsWork.tsGender = 'U';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Medium";
shirtLUMap['M'] = tsWork;
tsWork.tsCode = 'A';
tsWork.tsGender = 'F';
tsWork.tsCount = 0;
tsWork.tsValue = "";
tsWork.tsDescr = "Female X-Small";
shirtLUMap['A'] = tsWork;
[etc.]
Such code is tedious, and I'd like to learn some way to "shorthand"
the process of declaring certain default values. Using a non-default
constructor seems useful, but I don't know how I'd do it here... Please
advise.. TIA
Try this:
shirtLUMap tsLUMap = {
{'S', {"Small" ,"",'S','U',0}},
{'M', {"Medium","",'M','U',0}},
{'A', {"Female X-Small","",'A','F',0}}
};
in C++11 mode (untested).

Without C++11, you can still copy a statically initialized
C style vector into the map:

struct MapInit
{
char key;
TSINFO value;
operator shirtLUMap::value_type() const
{
return shirtLUMap::value_type( key, value );
}
};

static MapInit init[] =
{
{'S', {"Small" ,"",'S','U',0}},
{'M', {"Medium","",'M','U',0}},
{'A', {"Female X-Small","",'A','F',0}},
};
shirtLUMap theMap( begin( init ), end( init ) );
 

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

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top