tags:

views:

331

answers:

9

1) What is the convention used in practice when typedef'ing

something like

typedef std::map<SomeClass*, SomeOtherClass>  [SomeStandardName>]
typedef std::map<SomeClass*, std<SomeOtherClass> >  <[omeStandardName]

2) Where do you usually put typedef: header files globally, local to the class?

3) Do you typedef iterators or const map<> version?

4) Say you have map that used by two different concepts, do you create two separate typedefs them?

typedef map<string, SomeClass *> IDToSomeClassMap;
typedef map<string, SomeClass *> DescriptionToSomeClassMap;

Thanks


Edit #1

I am interested specifically in typedef STL maps, such as

typedef map<int, string> IdToDescriptionMap

or

typedef map<int, string> IdToDescription

What are common practices?

A: 

I don't know if there are any formal rules on the subject but I usually add type defs at the location most befitting the use within the project.

  • If the typedef is only used within one class then add the typedef inside the class definition
  • If the typedef is used by several unrelated classes add it in a header file at a namespace scope level

As for the actual name of the typedef'd type. I name it whatever makes sense for the typedef. I don't give typedef names any special convention such as prefixing with _t or anything along those lines. For example

typedef stl::map<stl::string,Student> NameToStudentMap;
JaredPar
A: 

None, just keep in mind the general rules for naming identifiers (no _ to begin with etc). Also, if your organization has a coding guideline, it is best to stick to it.

Often, when defining your own template class, it becomes messy without typedefs -- so I'd create them there as handy shortcuts. However, if it's really a bunch of classes, I'd rather have it at namespace level.

dirkgently
I am interested specifically in typedef STL maps, such as typedef map<int, string> IdToDescriptionMapor typedef map<int, string> IdToDescriptionWhat is the common practice?
I mentioned what we do in general -- no special rules for maps. FWIW, we may call a map<string, string> a Dict if it suits the object environment.
dirkgently
+1...........earned!!!
A: 

We use the following at my workplace:

typedef std::map WhateverMap;
typedef WhateverMap::iterator WhateverIter;
typedef WhateverMap::const_iterator WhateverCIter;

As far as location goes, that varies. If it's class-specific, it may be in an Impl structure, or may be in the protected or private areas of the class declaration. If it's more general (used across files, used in an API), we put it in a separate "FooTypes.h" style header.

Note that since it's common for us to sometimes change the underlying type, we may use "WhateverCollection" instead of "WhateverVec" or "WhateverList". It's not uncommon to have a "WhateverList" actually be typedefed to a vector or an slist, depending on desired footprint and performance characteristics.

leander
+2  A: 

There is no generally agreed rule on these names. What I usually do is to use the name of the "value" class suffixed with Map. In your example that would be SomeOtherClassMap. I use this convention because it is usually more interesting that your map contains "value" objects of type SomeOtherClass then that you look them up with "keys" of SomeClass.

lothar
+6  A: 

I prefer the following convention:

typedef std::map< Foo, Bar > FooToBarMap

I purposely avoid typedef'ing the iterators, I prefer explicitly referring to them as:

FooToBarMap::const_iterator

Since the iterators are already a de facto standard typename. And FooToBarMapConstIter is actually less clear to read when skimming code, I find.

Not Sure
A: 

Interest question:
I looked in boost, and I see they haven't any global rule, but most used convention

typedef std::map< key, value > some_domain_specific_name_map;

or

typedef std::map< key, value > some_domain_specific_name_map_type;

also good practice to make typedef for value_type or iterators, usually they have same name as map but with ending _value_type, _iterator.

bb
A: 

Normally I define related name to the typedef indicating the type of the object .

Ex:

typedef std::vector<ClassCompStudent*> StudentCollection;

typedef std::map<std::string /*id*/, ClassCompStudent* /*pStudent*/>  IDToStudentMap;

Also, I define them as public in class header in which the object has been created. That gives me the benefit of changing the container type without breaking client code.

class Test
{
public:
    typedef std::vector<ClassCompStudent*> StudentCollection;

    /* Users of Test need not know whether I use vector or list for 
     storing students. They get student collection and use it*/
    bool getStudents(StudentCollection& studentList) const;

    void print()
    {
     //do printing
    }
private:

    StudentCollection m_StudentList;
};

bool function(const Test& testObj)
{
    //If StudentCollection gets changed to list, this code need not be changed.
    StudentCollection aCollection;
    testObj.getStudents(aCollection);
    std::for_each(aCollection.begin(), aCollection.end(), std::mem_fun(&Test::print));
}
aJ
A: 

Using word "Map" or "Vector" in kind of useless notation. These are words connected to realization and not to the business model.

You don't have to show that this type is vector or map. You can use List. Like

typedef std::vector<std::string> List;
typedef std::set<std::string> List;

These both are lists of string. And this is true.

typedef std::map<std::string, Object> List;
or  
typedef std::map<std::string, Object> NamedList;

My point is don't use kind of hungarian notation.

Mykola Golubyev
+1  A: 

The second part of the question is the most interesting one to me. I prefer to put typedefs within the classes that use them, when there's a logical place for them, even if they're used in other classes. But that causes some problems with forward declarations (which we use heavily for compile-speed).

For example, in one recent project we had a class called Io, with an embedded typedef called Point, which made for very readable code -- an Io::Point is very clear and readable. But whenever we wanted to use the type, we had to include the declaration of the Io class, even if all we needed was the declaration of Io::Point, since there's no way (that I know of) to forward-declare a type that's within a forward-declared class.

In that case, we ended up doing it both ways. We created a global IoPoint type, and then typedefd Io::Point to it (so that our already-written code didn't have to be modified). Not the prettiest answer, but it got the job done.

As for the other parts:

We don't use any special convention for the names. For maps, we often use DescriptiveSomethingMap (since it's unlikely that we'll ever change from a map to some other container type), but if DescriptiveSomething is descriptive enough and doesn't conflict with an existing name, we'll often use it instead.

We generally don't bother creating typedefs for the iterators, since it's easy (and very readable) to simply use Type::iterator or Type::const_iterator. That said, we do sometimes typedef them if the type name is so long that Type::const_iterator makes the code look too "chunky." (Don't know of any better way to say it, but you probably know what I mean.)

We create different typedefs for each concept, even if two of them define exactly the same type. They can change independent of one another, so having different type names for them simplifies any later refactoring. It also makes for more readable code, in many cases.

Head Geek