naming convention when typedef standard collections

1.9k Views Asked by At

I am looking for naming conventions for typedef of lengthy collections definitions. We have some c++ code which used auto to get away with style murder, but we need to make this code compiling on a non c++11 compiler. We are looking to establish a convention for typedef of collections, which can become quite lengthy

For instance

typedef std::map<enum MyFirstEnum,enum MySecondEnum> map_enum2_by_enum1_t
typedef map_enum2_by_enum1_t::value_type             vtype_map_enum2_by_enum1_t
typedef map_enum2_by_enum1_t::iterator               map_iterator_enum2_by_enum1_t

There are so many nuances (iterator before t than at beginning, using type rather than t, ditching the prefix map, etc...) that half of the time you select one nuance, half of the time you select the other. At the end no typedef look like the other.

3

There are 3 best solutions below

0
On BEST ANSWER
typedef std::map<enum MyFirstEnum,enum MySecondEnum> map_enum2_by_enum1_t;

If there's no "big picture" name that better describes the mapping, then I'd suggest Enum2_By_Enum1 or Enum1_To_Enum2: both imply an associative container without the map bit, which is a bit too Hungarian for my taste, with all the same flaws (e.g. if you move to say unordered_map will you change it - if you remember - or leave it being misleading?).

typedef map_enum2_by_enum1_t::value_type             vtype_map_enum2_by_enum1_t;

I can't imagine this being useful... I'd typically only typedef a map's value_type inside a template when the concrete value type is unknown (e.g. the map or value type is one of the template parameters) and the map has no special or exclusive significance such that its value_type can reasonably be typedefed as the template's value_type, and in that scenario the map will necessarily have some other higher-level name reflecting its role in the template instantiation.

In conclusion, I'd omit this if at all possible and use enum2/MyFirstEnum directly.

typedef map_enum2_by_enum1_t::iterator               map_iterator_enum2_by_enum1_t;

There's no reason for this unless the typedef identifier is significantly shorter than what it aliases. Just use <mapname>::iterator.

If you think you've got specific examples of code that's improved by having these last two typedefs, please share it.

0
On

There are all sorts of ways.

Usually, I would aim to avoid the problem from the beginning, by deriving the typenames from the top level design rather than from types used to implement it. From a top level perspective, there is usually some concept that a type represents, and that concept is usually a suitable name - right from early design. Retrofitting things like type names onto existing sloppy code is really a bad idea.

But, given that this is your starting point, I suggest not being too lavish in adorning the names and do something like this.

namespace <libname>_Type
{
      typedef std::map<FirstEnum, SecondEnum> map_first_second;
      typedef map_first_second::value_type map_first_second_value;
      typedef map_first_second::iterator map_first_second_iterator;
      typedef map_first_second::const_iterator map_first_second_const_iterator;

}

or (if your library has its own namespace)

namespace <libname>
{
     namespace Type
     {
          typedef std::map<FirstEnum, SecondEnum> map_first_second;
          typedef map_first_second::value_type map_first_second_value;
          typedef map_first_second::iterator map_first_second_iterator;
          typedef map_first_second::const_iterator map_first_second_const_iterator;

     }
}

Now, okay, the use of namespaces may make mean a bit more work to set up, but using the types is easier.

for (<libname>::Type::map_first_second_iterator i, end = some_map.end();
      i != end;
      ++i)
{
   do_something(i);
}

which can be simplified to avoid all the scoping with a judicious using.

If your style guidelines allow or require, it is possible to avoid use of underscore by using camel-case (e.g. instead of map_first_second_iterator use MapFirstSecondIterator. The key, for developers, is being consistent in using your naming conventions and not over-complicating it, rather than having a perfect one.

0
On

All this is obviously subjective. That said, I tend to use a namespace to separate/isolate types, and keep names small/short:

enum foo_result;
enum bar_state;
enum baz_values;

namespace mappings { // namespace name tells you what's inside, so there is
                     // no need to call names inside with "map_" prefix

    // "associate foo_result to bar_state"
    typedef std::map<foo_result,bar_state> foo_result2bar_state;

    // "associate foo_result to baz_values"
    typedef std::map<foo_result,baz_values> foo_result2baz_values;

    // I would not define these here:
    // typedef foo_result2bar_state::value_type
    //    foo_result2bar_state_value_type;
}

Client code then becomes self-descriptive:

void f(mappings::foo_result2bar_state& m) // foo_result2bar_state is a "mapping" of types
{
    // I prefer to have this alias in client code (i.e. where I use it)
    typedef mappings::foo_result2bar_state::iterator itr;

    itr begin = m.begin();
    // ...
}