如果不使用示例来说这个问题有点难,所以我会对此有所了解。
作为一个基本的例子,boost::intrusive::list
有一些有趣的模板,我很难弄清楚它们是如何工作的。类规范看起来有点像这样:
template<typename T, class... Options>
class list {
...
};
我的重点是Options
参数。对于初学者来说,它是可变的。这在c ++ 11中是“微不足道的”,因为它受语言支持。当然很容易在c ++ 03中进行模拟(最多可以有10个参数,都有一些默认的令牌值)。
这是我的问题:
Options
可以使用任意数量的“选项”类型,按任意顺序。例如:
typedef list<Foo, constant_time_size<false> > FooList;
或
//This option will configure "list" to use the member hook
typedef member_hook<Foo, list_member_hook<>, &Foo::hook_> MemberHookOption;
//This list will use the member hook
typedef list<Foo, MemberHookOption> FooList;
这真的很酷......他们如何使这项工作适用于所有不同的组合。如果我两次传递相同类型的选项会怎样?对于boost::instrusive::list
,可能的选项是:
base_hook<class Hook> / member_hook<class T, class Hook, Hook T::* PtrToMember> / value_traits<class ValueTraits>
:所有这些选项都指定了要插入列表中的类型T与钩子之间的关系(因为我们可以在同一个T类型中有多个钩子)。稍后将解释member_hook,并在带有自定义ValueTraits部分的容器中解释value_traits。如果未指定任何选项,则容器将配置为使用带有默认标记的基本挂钩。为钩子配置的一些选项(指针的类型,链接模式等)将传播到容器。
constant_time_size<bool Enabled>
:指定是否要求容器使用常量时间size()函数。这将指示侵入式容器存储额外的成员以跟踪容器的当前大小。默认情况下,会激活常量时间大小。
size_type<bool Enabled>
:指定可以容纳容器大小的类型。如果请求constant_time_size,则此类型将是list.size()返回的类型以及存储在侵入容器中的类型。用户通常不需要更改此类型,但某些容器的size_type可能与std :: size_t不同(例如,类似STL的容器使用其分配器定义的size_type)。 Boost.Intrusive可用于实现指定大小类型的此类容器。默认情况下,类型为std :: size_t。
我喜欢这个概念,因为它允许对类型的行为进行编译定义。但是你可以想象,各种组合可能变得复杂。我猜测通过一些魔术,他们将选项标准化为一个简单的结构,可以用于真正的数据结构。但这只是猜测工作:-P
答案 0 :(得分:1)
在尝试使用Policy Base设计时,我已经做了几次。
我使用的核心思想是政策被标记(通过内部typedef,类似于迭代器的iterator_category
),然后我定义了一个简单地遍历列表并提取给定策略的类一个类别,如果两个策略引用同一类别,则会引发编译错误。类似的东西:
template <typename Tag, typename Opt, typename... Options>
struct CategoryExtractorImpl {
typedef typename if_<
same_type<typename Opt::Tag, Tag>,
Opt,
void
>::type Lhs;
typedef typename CategoryExtractorImpl<Tag, Options...>::type Rhs;
typedef typename Combinator<Lhs,Rhs>::type type;
};
if_
只根据谓词在两种类型中进行选择,组合符写为:
template <typename, typename> struct Combinator;
template <typename L> struct Combinator<L, void> { typedef L type; };
template <typename R> struct Combinator<void, R> { typedef R type; };
template <> struct Combinator<void, void> { typedef void type; };
当然,您还需要提供默认值,因为根本不提供该策略。
template <typename L, typename R> struct ForgivingCombinator { typedef L type; };
template <typename R> struct ForgivingCombinator<void, R> { typedef R type; };
最后,你得到:
template <typename Default, typename... Options>
struct CategoryExtractor {
typedef typename ForgivingCombinator<
typename CategoryExtactorImpl<typename Default::Tag, Options...>::type
Default
>::type type;
};
使用此功能,您只需轻松提取所有类别:
template <typename... Options>
class List {
typedef typename CategoryExtractor<DefaultPolicyX, Options...>::type PolicyX;
typedef typename CategoryExtractor<DefaultPolicyY, Options...>::type PolicyY;
...
};
当然,在典型的基于策略的设计中,它可能会变得更加冗长,因为您将从它们中私下继承(触发EBO),然后在需要时重复类中的实际类型。