3

通过将类型的属性与其定义分开, Catch-all tr​​aits 类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.

这更清晰,因为不需要违反成语来处理首先需要花哨的步法的任何特殊情况。主要特征模板不会产生缺少客户端类不适合某些东西的内部错误,根本不需要任何主要特征模板。

从概念上讲,将类的质量与其服务的实现分开会更好,无论这种分离是否必要。但是,这种风格确实需要将每个客户端类分成两部分,包括一个显式的专业化,这有点难看。


有人熟悉这个设计空间吗?我倾向于第二个成语,尽管它在实践中看起来很不寻常。但是,以前在这里踩过的人可能都知道来龙去脉。

4

1 回答 1

1

将用户定义的特征作为库类型的特化的问题在于库类型属于该库。定义显式特化需要打开库名称空间,这很丑陋。

备选方案 1 和 2 可以组合成两全其美的模式,

  • 总是允许关注点的最佳分离(通过将一个类分成特征和实现)
  • 不需要拆分班级
  • 从不需要打开库命名空间

需要以基于 ADL 的元函数将任何类映射到其特征的形式进行额外的粘合。

template< typename t >
t traits_type_entry( t const & ); // Declared, never defined.

template< typename t >
using traits_type = decltype( traits_type_entry( std::declval< t >() ) );

默认情况下,按原样T用作其自己的特征类型。要将给定类型的此更改为特征类,请声明(但不定义)一个函数。这个类可能是也可能不是; 设施不在乎。因为该函数将通过参数依赖查找找到,所以它可能被声明为在命名空间范围内没有声明的友元函数。traits_type< T >::typeTtt_traitst_traits traits_type_entry( t const & )t_traitsttraits_type

嵌套在类中的用法(只是为了制作一个困难的测试用例)看起来像这样。对于命名空间中的常规用法,只需删除friend关键字。

class outer_scope {
    struct special;
    struct special_traits {
        typedef int value_type;
        constexpr static int limit = 5;
    };
    friend special_traits traits_type_entry( special const & );

    struct unspecial {
        typedef double baz_type;
        int table[ util::traits_type< special >::limit ];
    };

    struct special : special_traits {
        void f() {
             std::pair< typename util::traits_type< unspecial >::baz_type,
                        value_type >();
        }
    };
};

http://ideone.com/QztQ6i

注意,只要类是可复制和可破坏的,t const &参数 totraits_type_entry可以很简单。t

t此外,您可以通过让主模板返回一个派生自其构造函数的类型而不是其t自身来防止声明(非自定义)特征类型的对象。

于 2013-11-08T06:55:30.513 回答