C++ sometimes uses the suffix _type
on type definitions (e.g. std::vector<T>::value_type
),
also sometimes _t
(e.g. std::size_t
), or no suffix (normal classes, and also typedefs like std::string
which is really std::basic_string<...>
)
Are there any good conventions on when to use which name?
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. Comparestd::vector<T>::value_type
andstd::vector<T>::size_type
, which come from the vector's template parametersT
andAllocator
, respectively, againststd::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). Withtrue_type
andfalse_type
, it is indeed a suffix (sincetrue
andfalse
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
orsomething_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, thenauto
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 typeX::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 (includingstd::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.As a C heritage the
_t
(that used to mean "defined viatypedef
") 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 enumsSo, here's the thing: the identifier
foo_type
can be interpreted asfoo
's" (e.g.size_type overall_size = v1.size() + v2.size();
)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; 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 asl - what happens if you have enums within classes? Well, I try to avoid those, and place my enum inside the surrounding namespace.