【发布时间】:2013-11-08 04:30:01
【问题描述】:
像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 中声明的事实。我试图对用户代码中可能发生的事情进行熟悉的说明。)
这更简洁,因为不需要违反成语来处理首先需要花哨的步法的特殊情况。与其让主要特征模板产生缺失的客户端类不适合某些东西的内部错误,不如根本不需要任何主要特征模板。
从概念上讲,将类的质量与其服务的实现分开会更好,无论这种分离是否必要。但是,这种风格确实需要将每个客户端类分成两部分,包括显式特化,这有点难看。
有人熟悉这个设计空间吗?我倾向于第二个成语,尽管它在实践中看起来很不寻常。但是,那些曾经在这里踩过的人可能都知道其中的来龙去脉。
【问题讨论】:
标签: c++ design-patterns idioms typetraits