通过将类型的属性与其定义分开, Catch-all traits 类std::iterator_traits
很有用,例如,可以在定义完成之前使属性可用。
除了每个客户端类本身之外定义特征是不方便的,因为特征通常也有作为成员的位置。std::iterator_traits
这就是为什么根据其模板参数的成员来定义的通用实现。
template< typename it >
struct iterator_traits {
typedef typename it::category category;
typedef typename it::value_type value_type;
// etc
};
使用继承不是更容易,编译器的工作量也更少吗?
template< typename t >
struct t_traits : public t {
t_traits() = delete; // Prevent runtime instances.
};
这无法在主模板中记录界面,但无论如何还有其他机会。
编写大量重复代码来定义元容器类似乎毫无意义,甚至不能保证防止诸如在运行时创建这样的滥用。
或者这完全是倒退。除了std::iterator_traits
我们还有std::iterator
一个伪抽象基类,其成员大多相同。这种冗余是一种代码味道。如果自定义迭代器看起来像这样不是更好吗?
template<>
struct iterator_traits< struct my_iterator > {
typedef random_access_iterator_tag category;
typedef foo value_type;
...
};
struct my_iterator : iterator_traits< struct my_iterator > {
...
};
(为了争论,让我们忽略一个实际的特化std::iterator_traits
必须在namespace std
.
这更清晰,因为不需要违反成语来处理首先需要花哨的步法的任何特殊情况。主要特征模板不会产生缺少客户端类不适合某些东西的内部错误,根本不需要任何主要特征模板。
从概念上讲,将类的质量与其服务的实现分开会更好,无论这种分离是否必要。但是,这种风格确实需要将每个客户端类分成两部分,包括一个显式的专业化,这有点难看。
有人熟悉这个设计空间吗?我倾向于第二个成语,尽管它在实践中看起来很不寻常。但是,以前在这里踩过的人可能都知道来龙去脉。