C++ type suffix _t, _type or none
As a C heritage the _t
(that used to mean "defined via typedef
") syntax has been inherited (they're also SUS/POSIX-reserved in the global namespace).
Types added in C++ and not present in the original C language (e.g. size_type
) don't need to be shortened.
Keep in mind that to the best of my knowledge this is more of an observation on an established convention rather than a general rule.
My answer is only relevant for type names within namespaces (that aren't std
).
Use no suffix usually, and _type
for enums
So, here's the thing: the identifier foo_type
can be interpreted as
- "the identifier of the type for things which are
foo
's" (e.g.size_type overall_size = v1.size() + v2.size();
) - "the identifier of the type for things which are kinds, or types, of foo" (e.g.
employment_type my_employment_type = FIXED_TERM;
)
When you have typedef'ed enums in play, I think you would tend towards the second interpretation - otherwise, what would you call your enum types?
The common aversion to using no suffix is that seeing the identifier foo
is confusing: Is it a variable, a specific foo? Or is it the type for foos? ... luckily, that's not an issue when you're in a namespace: my_ns::foo
is obviously a type - you can't get it wrong (assuming you don't use global variables...); so no need for a prefix there.
PS - I employ the practice of suffixing my typedef's within classes with _type
(pointer_type
, value_type
, reference_type
etc.) I know that contradicts my advice above, but I somehow feel bad breaking with tradition on this point.
Now, you could ask - what happens if you have enums within classes? Well, I try to avoid those, and place my enum inside the surrounding namespace.
As @MarcoA.'s answer correctly points out, the suffix _t
is largely inherited from C (and in the global namespace - reserved for POSIX).
This leaves us with "no suffix" and _type
.
Notice that there is no namespace-scope name in std
ending in _type
*; all such names are members of classes and class templates (or, in the case of regex-related types, of a nested namespace which largely plays a role of a class). I think that's the distinction: types themselves don't use the _type
suffix.
The suffix _type
is only used on members which denote types, and moreover, usually when they denote a type somewhat "external" to the containing class. Compare std::vector<T>::value_type
and std::vector<T>::size_type
, which come from the vector's template parameters T
and Allocator
, respectively, against std::vector<T>::iterator
, which is "intrinsic" to the vector class template.
* Not entirely true, there are a few such names (also pointed out in a comment by @jrok): common_type
, underlying_type
, is_literal_type
, true_type
, false_type
. In the first three, _type
is not really a suffix, it's an actual part of the name (e.g. a metafunction to give the common type or the underlying type). With true_type
and false_type
, it is indeed a suffix (since true
and false
are reserved words). I would say it's a type which represents a true/false value in the type-based metaprogramming sense.
Member types are called type
or something_type
in the C++ standard library. This is readable and descriptive, and the added verbosity is not usually a problem because users don't normally spell out those type names: most of them are used in function signatures, then auto
takes care of member function return types, and in C++14 the _t
type aliases take care of type trait static type members.
That leads to the second point: Free-standing, non-member types are usually called something_t
: size_t
, int64_t
, decay_t
, etc. There is certainly an element of heritage from C in there, but the convention is maintained in the continuing evolution of C++. Presumably, succinctness is still a useful quality here, since those types are expected to be spelled out in general.
Finally, all the above only applies to what I might call "generic type derivation": Given X
, give me some related type X::value_type
, or given an integer, give me the 64-bit variant. The convention is thus restricted to common, vocabulary-type names. The class names of your actual business logic (including std::string
) presumably do not warrant such a naming pattern, and I don't think many people would like to have to mangle every type name.
If you will, the _t
and _type
naming conventions apply primarily to the standard library and to certain aspects of the standard library style, but you do not need to take them as some kind of general mandate.