Naprawdę nie zgadzam się z tą konwencją nazewnictwa. Dla mnie parametry szablonu reprezentujące w pełni rodzajowy typ mają sens jako prosta litera - to jest typ T
, naprawdę nie obchodzi mnie, który. Ale jeśli są jakieś wymagania co do typu, sensowne jest utworzenie nazwy, która identyfikuje to, co jest argumentem szablonu: template <typename T, typename Allocator> struct container
- pierwszy typ jest ogólny, dowolny T
zmieści się, ale drugi to alokator.
Nie inaczej jest z funkcjami, których nie chcą parametry nazywać a
, b
... w kolejności lub wyglądu, lecz wytwarzają znaczących nazw jako część dokumentacji. Ponadto, jeśli opracowuję przewodnik stylu, rozważam wymaganie lokalnych typów argumentów szablonu w przypadku klas szablonów wraz z statycznymi twierdzeniami na temat wymagań dla typów (jeśli to możliwe). To znaczy, przynajmniej do pojęć zapewniających tę funkcjonalność.
Uważam, że STL jest dobrym przykładem biblioteki i widać, że generowanie pomocy pomaga w odczytaniu kodu (z g ++ 4.2 STL):
Ćwiczenia:
// from <vector> -> <bits/stl_vector.h>
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>
{
// Concept requirements.
typedef typename _Alloc::value_type _Alloc_value_type; // _Alloc contains value_type internal type
__glibcxx_class_requires(_Tp, _SGIAssignableConcept) // _Tp is assignable
[...]
public:
typedef _Tp value_type; // from here on _Tp is not mentioned
typedef typename _Tp_alloc_type::reference reference; // check + typedef
[...]
iterator begin() {
// without typedef:
// __gnu_cxx::__normal_iterator<pointer, vector_type> begin() {
[...]
reference operator[](size_type __n)
// _Tp& operator[](size_type __n)
[...]
// from <memory>
template <typename _Tp>
class auto_ptr
{
[...]
template <typename _Tp1>
auto_ptr(auto_ptr<_Tp1>& __a) throw()
i funkcje:
template <typename _InputIterator, typename _Tp>
inline _InputIterator find(_InputIterator __first, _InputIterator __last, _Tp value) {
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
[...]
Wszystkie ich nazwy są poprzedzone _
i albo litery lub drugiego _
, które to nazwy zastrzeżone do implementacji i wolą _Tp
od _T
, ale na końcu widać, że zawsze gdy typ to generyczny nazywa się _Tp
, _Tp1
..., podczas gdy w przypadku niektórych specyficznych wymagań jest on przypisany, wybiera się bardziej sensowną nazwę.
Istnieje cienka linia między nimi, jak na przykład w std::vector
istnieją rzeczywiste wymagania dotyczące typu rodzajowego: _Tp
muszą być przypisane, ale pod koniec dnia, to jest głównie typ rodzajowy. Nazywanie go _Assignable
byłoby dziwne w niektórych pojemnikach, gdzie istnieje więcej niż jedno wymaganie.
Jak pisałeś '_' lub' __ * 'są zarezerwowane dla implementacji (w pewnych zakresach), więc IMHO lepiej jest trzymać się z daleka od używania dowolnego tak nazwanego identyfikatora (nawet jeśli prawdopodobnie nie spowoduje żadnej szkody w ćwiczyć). –