I would like to ask the proper location of typedef in C++.
Version1 : typedef outside class
typedef std::pair<std::string, int> StrIntPair;
typedef std::vector<StrIntPair> StrIntPairVec;
class MyData
{
public:
MyData(){};
~MyData(){};
private:
void addInfo(const StrIntPair &info)
{
infoVec.push_back(info);
}
StrIntPair info;
StrIntPairVec infoVec;
};
Version2 : typedef inside class public
class MyData
{
public:
MyData(){};
~MyData(){};
typedef std::pair<std::string, int> StrIntPair;
typedef std::vector<StrIntPair> StrIntPairVec;
private:
void addInfo(const StrIntPair &info)
{
infoVec.push_back(info);
}
StrIntPair info;
StrIntPairVec infoVec;
};
Version3 : typedef inside class private
class MyData
{
public:
MyData(){};
~MyData(){};
private:
typedef std::pair<std::string, int> StrIntPair;
typedef std::vector<StrIntPair> StrIntPairVec;
void addInfo(const StrIntPair &info)
{
infoVec.push_back(info);
}
StrIntPair info;
StrIntPairVec infoVec;
};
Which version is the best practice?
First way is to typedef at the place-of-first-declaration. Second way is to typedef at each place-of-use, and make it only visible to that place-of-use (by putting it inside the class or method that uses it).
typedef is a reserved keyword in the programming languages C and C++. It is used to create an additional name (alias) for another data type, but does not create a new type, except in the obscure case of a qualified typedef of an array type where the typedef qualifiers are transferred to the array element type.
A typedef declaration is a declaration with typedef as the storage class. The declarator becomes a new type. You can use typedef declarations to construct shorter or more meaningful names for types already defined by C or for types that you have declared.
The C language contains the typedef keyword to allow users to provide alternative names for the primitive (e.g., int) and user-defined (e.g struct) data types. Remember, this keyword adds a new name for some existing data type but does not create a new type.
This depends on where you use the type alias. I'd advice you to
The compiler will only enforce scopes of aliases that are too narrow (e.g. you use a type alias defined in the private section of your class outside of that class) and won't complain if you choose an unnecessarily permissive scope (e.g. you publicly declare the alias, but use it only in the class implementation). Hence, strive to choose the narrowest scope possible, which is in line with hiding implementation details.
As a side note, you might want to consider declaring your type aliases with using StrIntPair = std::pair<std::string, int>;
, see Item 9 in Effective Modern C++. This has no influence on the above, though.
The question is about logical namespace of those names. With abstract naming like StrIntPair
, StrIntPairVec
and MyData
there are no answers. Answers come when the things have meaning.
Lets take exactly same data structures but name them NickAndId
, Friends
and Player
.
Now the question if to put NickAndId
inside Player
is about if it is specific to player. Can other entities like NonPlayerCharacter
or Creature
also have nickname and id expressed as same pair? Possibly. Then it should be outside.
Same question should be asked about Friends
. Likely the NonPlayerCharacter
and Creature
can have nickname and id but do not have friends? Then it makes sense to put the type inside of Player
as Player::Friends
.
Finally, the types that are made private are meant only for usage by implementation details. That should be used when the name makes perfect sense in algorithms used inside of class but availability of those outside is unneeded or even worse, confusing. For example NonPlayerCharacter
can react with some replicas to some states whose values are also internal to that NPC. Keeping that in sorted vector Reactions
makes perfect sense inside of class. Access to ReplicaInState
and Reactions
from outside can be confusing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With