c++ - 特质和政策有什么区别?

标签 c++ template-meta-programming typetraits policy-based-design

我有一个类,我正在尝试配置其行为。

template<int ModeT, bool IsAsync, bool IsReentrant> ServerTraits;
然后我有我的服务器对象本身:
template<typename TraitsT>
class Server {…};
我的问题是我上面的用法是我的命名错误吗?我的模板化参数实际上是策略而不是特征吗?
什么时候模板化参数是特征还是策略?

最佳答案

政策

策略是类(或类模板)到 注入(inject)行为 进入父类,通常通过继承。通过将父接口(interface)分解为正交(独立)维度,策略类形成了更复杂接口(interface)的构建块。一种常见的模式是将策略作为用户可定义的模板(或模板模板)参数提供,并带有库提供的默认值。标准库中的一个例子是分配器,它们是所有 STL 容器的策略模板参数

template<class T, class Allocator = std::allocator<T>> class vector;

在这里,Allocator模板参数(它本身也是一个类模板!)将内存分配和释放策略注入(inject)父类 std::vector .如果用户不提供分配器,则默认 std::allocator<T>用来。

作为基于模板的多态性的典型,策略类的接口(interface)要求是 隐含语义 (基于有效表达式)而不是显式和句法(基于虚成员函数的定义)。

请注意,最近的无序关联容器具有多个策略。除了通常的 Allocator模板参数,他们也带一个 Hash默认为 std::hash<Key> 的策略函数对象。这允许无序容器的用户沿多个正交维度(内存分配和散列)配置它们。

性状

特征是 的类模板提取属性 从泛型类型。有两种特征:单值特征和多值特征。单值特征的例子是来自标题 <type_traits> 的那些特征。
template< class T >
struct is_integral
{
    static const bool value /* = true if T is integral, false otherwise */;
    typedef std::integral_constant<bool, value> type;
};

单值特征常用于 模板元编程和 SFINAE 技巧根据类型条件重载函数模板。

多值特征的例子是来自头部的 iterator_traits 和 allocator_traits <iterator><memory> , 分别。由于特征是类模板,它们可以被特化。下面是 iterator_traits 特化的例子为 T*
template<T>
struct iterator_traits<T*>
{
    using difference_type   = std::ptrdiff_t;
    using value_type        = T;
    using pointer           = T*;
    using reference         = T&;
    using iterator_category = std::random_access_iterator_tag;
};

表达式 std::iterator_traits<T>::value_type可以使成熟的迭代器类的通用代码甚至可用于原始指针(因为原始指针没有成员 value_type )。

策略和特征之间的交互

在编写您自己的通用库时,重要的是要考虑用户可以专门化您自己的类模板的方式。但是,必须小心,不要让用户成为 的受害者。一个定义规则 通过使用特征的特化来注入(inject)而不是提取行为。转述这个 old post安德烈亚历山德雷斯库

The fundamental problem is that code that doesn't see the specialized version of a trait will still compile, is likely to link, and sometimes might even run. This is because in the absence of the explicit specialization, the non-specialized template kicks in, likely implementing a generic behavior that works for your special case as well. Consequently, if not all the code in an application sees the same definition of a trait, the ODR is violated.



C++11 std::allocator_traits通过强制所有 STL 容器只能从其 Allocator 中提取属性来避免这些陷阱。政策通过 std::allocator_traits<Allocator> .如果用户选择不提供或忘记提供某些必需的策略成员,则traits 类可以介入并为那些缺失的成员提供默认值。因为 allocator_traits本身不能被专门化,用户总是必须通过一个完全定义的分配器策略来自定义他们的容器内存分配,并且不会发生静默 ODR 违规。

请注意,作为库编写者,您仍然可以专门化特征类模板(如 iterator_traits<T*> 中的 STL 所做的那样),但是通过策略类将所有用户定义的专门化传递为可以提取特征的多值特征是一种很好的做法特殊行为(如 STL 在 allocator_traits<A> 中所做的那样)。

更新 :traits 类的用户定义特化的 ODR 问题主要发生在将 trait 用作 时。全局类模板并且您不能保证所有 future 的用户都会看到所有其他用户定义的特化。政策是本地模板参数 并包含所有相关定义,允许用户自定义它们而不会干扰其他代码。只包含类型和常量——但不包含行为函数——的本地模板参数可能仍被称为“特征”,但它们对其他代码(如 std::iterator_traits)不可见。和 std::allocator_traits .

关于c++ - 特质和政策有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14718055/

相关文章:

c++ - 如何使用 Windows 程序在 C++ 中获取控制台输出?

c++ - 如何使用 Boost hana 递归创建 constexpr 列表?

c++ - 指向成员的指针,在类中

c++ - C++ 中是否可以使用条件类型定义?

c++ - 类型特征和特定行为

c++ - 在包装类的枚举中定义静态 constexpr 值

c++ - 非虚推导: what do I really get from the compiler?

c++ - freeglut/glu 3d 绘图

c++ - 使用模板元编程的功能省略?

c++ - 为两种 vector 类型或一种 vector 类型与标量类型之间的二元运算结果确定正确的大小类型