当前位置: 首页 > 知识库问答 >
问题:

如何为作用域分配器模型启用自定义容器

卞成荫
2023-03-14

这是一篇很长的文章,所以我想在顶部写下唯一的问题:

似乎我需要为一个自定义容器实现“allocator extended”构造函数,该容器本身不使用分配器,而是将其传播到其内部实现,该实现是一个变量类型,其允许的类型可能是一个容器,如std::map,但也可能是一个不需要分配器的类型,比如布尔值。

独自一人,我不知道如何做到这一点。

非常感谢您的帮助!;)

“定制容器”是一个类模板value,它是JSON数据结构表示的实现。

Class templatevalue是一个薄薄的包装,围绕着一个有区别的联合:Class templatevariant(类似于boost variant)。此变量允许的类型表示JSON类型对象、数组、字符串、布尔数和Null。

类模板value有一个可变的模板模板参数包Policies,它基本上定义了JSON类型的实现方式。默认情况下,JSON类型是用std::map(用于对象)、std::向量(用于数组)、std::字符串(用于JSON数据字符串)和一些自定义类实现的表示剩余的JSON类型。

value中定义的类型机制用于根据给定的策略以及value本身为容器类型创建递归类型定义。(例如,当variant类使用std::map或std::vector时,它不需要使用“递归包装器”来实现JSON容器)。也就是说,这种类型机制创建了用于表示JSON类型的实际类型,例如,对于value\u-type等于value的数组,创建了std::map,对于映射的\u-type等于value的对象,创建了std::map。(是的,value在生成类型时实际上是不完整的)。

类模板基本上如下所示(大大简化):

template <template <typename, typename> class... Policies>
class value
{
    typedef json::Null                          null_type;
    typedef json::Boolean                       boolean_type;
    typedef typename <typegenerator>::type      float_number_type;
    typedef typename <typegenerator>::type      integral_number_type;
    typedef typename <typegenerator>::type      string_type;
    typedef typename <typegenerator>::type      object_type;
    typedef typename <typegenerator>::type      array_type;


    typedef variant<
        null_type
      , boolean_type
      , float_number_type
      , integral_number_type
      , string_type
      , object_type
      , array_type
    > variant_type;

public:

    ...

private:
    variant_type value_;
};

value实现了常见的可疑函数,例如构造函数、赋值、访问器、比较器等。它还实现了转发构造函数,以便可以使用参数列表构造变量的特定实现类型。

typegenerator基本上会找到相关的实现策略并使用它,除非它没有找到,然后它会使用默认的实现策略(这里没有详细说明,但是请询问是否有不清楚的地方)。

例如,数组类型变为:std::vector

到目前为止,这是预期的。

现在,我们的想法是让用户能够指定一个自定义分配器,用于“容器”中的所有分配和所有构造,即value。例如,竞技场分配器。

为此,我扩展了value的模板参数如下:

template <
    typename A = std::allocator<void>,
    template <typename, typename> class... Policies
>
class value ...

并且还调整了类型机械,以便在适当时使用作用域分配程序适配器

请注意,模板参数A不是value的分配器类型,而只是在类型机器中使用,以生成正确的实现类型。也就是说,中没有嵌入的分配器类型——但它会影响实现类型的分配器类型。

现在,当使用状态自定义分配器时,这只能起到一半的作用。更准确地说,它是有效的——除非作用域分配器的传播不会正确发生。例如。:

假设,有一个具有属性id的状态型自定义分配器,它是一个整数。它不能是默认构造的。

    typedef test::custom_allocator<void> allocator_t;
    typedef json::value<allocator_t> Value;
    typedef typename Value::string_type String;
    typedef Value::array_type  Array;

    allocator_t a1(1);
    allocator_t a2(2);

    // Create an Array using allocator a1:
    Array array1(a1);
    EXPECT_EQ(a1, array1.get_allocator());

    // Create a value whose impl-type is a String which uses allocator a2:
    Value v1("abc",a2);

    // Insert via copy-ctor:
    array1.push_back(v1);

    // We expect, array1 used allocator a1 in order to construct internal copy of value v1 (containing a string):
    EXPECT_EQ(a1, array1.back().get<String>().get_allocator());
  --> FAILS !!

原因似乎是,array1不会通过值v1的副本将其分配器成员(即a1)传播到其当前imp类型,即字符串的实际副本。

也许这可以通过值中的“分配器扩展”构造函数来实现,尽管它本身并不使用分配器,而是需要在需要时适当地“传播”它们。

但是我如何才能做到这一点呢?

编辑:显示类型生成的一部分:

“Policy”是一个模板参数,其第一个参数是value_类型(在本例中为value),第二个参数是分配器类型。“策略”定义了如何根据值类型和分配器类型实现JSON类型(例如数组)。

例如,对于JSON数组:

template <typename Value, typename Allocator>
struct default_array_policy : array_tag
{
private:
    typedef Value value_type;
    typedef typename Allocator::template rebind<value_type>::other value_type_allocator;
    typedef GetScopedAllocator<value_type_allocator> allocator_type;
public:
    typedef std::vector<value_type, allocator_type> type;
};

其中,GetScopedAllocator定义为:

template <typename Allocator>
using GetScopedAllocator = typename std::conditional<
    std::is_empty<Allocator>::value,
    Allocator,
    std::scoped_allocator_adaptor<Allocator>
>::type;

共有1个答案

岑熙云
2023-03-14

决定是否将分配器传递给子元素的逻辑在标准中称为uses-allocator构造,请参见20.6.7[allocator.uses]。

有两个使用uses分配器协议的标准组件:std::tuplestd::scoped_分配器_适配器,您还可以编写用户定义的分配器来支持它(但通常更容易使用scoped_分配器_适配器向现有分配器添加对协议的支持)

如果您在value中内部使用scoped\u分配器\u适配器,那么您需要做的就是确保value支持uses分配器构造,这是由std::uses\u分配器指定的

namespace std
{
  template<typename A, typename... P, typename A2>
    struct uses_allocator<value<A, P...>, A2>
    : is_convertible<A, A2>
    { };
}

这将意味着,当一个value由支持uses-allocator构造的类型构造时,它将尝试将分配器传递给value构造函数,因此您还需要添加分配器扩展构造函数,以便可以传递...

为了让它像你想要的那样工作:

// Insert via copy-ctor:
array1.push_back(v1);

custom\u分配器模板必须支持uses分配器构造,或者您必须对其进行包装,以便Value::array\u type::allocator\u type作用域分配器\u适配器

当然,标准库实现必须支持范围分配器,您使用的编译器是什么?我只熟悉GCC在这方面的状态,其中GCC 4.7仅支持d::向量。对于GCC 4.8,我也添加了对forward_list的支持。我希望剩余的集装箱将全部完成GCC 4.9。

注意:对于所有与分配器相关的操作,您的类型也应该使用std::allocator\u traits,而不是直接调用分配器类型上的成员函数。

是的,值在生成类型时实际上是不完整的

除非另有说明,否则在实例化标准模板组件时使用不完整类型作为模板参数是未定义的行为,请参见17.6.4.8[res.on.functions]。它可能适用于您的实现,但不是必需的。

 类似资料:
  • 英文原文:http://emberjs.com/guides/models/customizing-adapters/ 在Ember Data中,处理与后台数据仓库通信的逻辑是通过Adapter来完成的。Ember Data适配器内置了一些关于REST API的假定。如果后台的实现与Ember Data假定的惯例不同,那么通过扩展缺省的适配器可能很容易的实现。 有时因为一些原因需要自定义适配器,例

  • 问题内容: 这些天,我读了很多关于如何设置和运行Docker堆栈的信息。但是我一直想念的一件事是如何设置特定容器通过域名响应访问权限,而不仅仅是使用docker dns的容器名称。 我的意思是说我有一个可以从外部访问的微服务,例如:users.mycompany.com,它将进入处理用户api的微服务容器 然后,当我尝试访问customer-list.mycompany.com时,它将进入处理客户

  • 我们有一个Spring booter应用程序,它的父级定义为spring-boot-starter-父级。但在我们的项目中,我们有一个父pom,其中定义了分发管理,项目中的所有子模块都继承自它。现在,由于Spring booter应用程序已经继承自spring-boot-starter-父级,并且我不想重复分发管理,我想拥有一个自定义的Spring booter模块,以便能够在其中定义分发管理,然

  • 问题内容: 我有一个Dockerfile和自定义Nginx配置文件(与Dockerfile位于同一目录中),如下所示: Dockerfile: nginx.conf文件: 我运行以下两个命令: 然后,我签出了所有正在运行的容器,但没有显示出来。当我搜索nginx容器的日志时,发现以下错误消息: [emerg] 1#1:/etc/nginx/nginx.conf中的未知指令“上游”:1 nginx:

  • 问题内容: 我想将非spring bean类对象用作球衣Web服务类方法的参数。但是它在构建时会给出缺少的依赖项错误。 我的代码是: 问题答案: 关键是路径参数以字符串形式出现。根据规范,如果我们希望将自定义类型作为注入,则自定义类应具有以下三项之一: 返回类型的公共静态 返回类型的公共静态 或接受字符串的公共构造函数 另一种选择实现。您可以在此处查看示例。 如果您不拥有该类(它是无法更改的第三方

  • 我试图使用OpenNLPJavaAPI从文档中提取名称、技能等实体。但它没有提取正确的名称。我使用opennlp源锻造链接上可用的模型 下面是一段java代码- 我想做的是: 我正在使用ApacheTika将PDF文档转换为纯文本文档 但它正在提取姓名和其他单词。它不是提取专有名称。如何创建自定义模型,从文档中提取游泳、编程等技能? 给我一些想法! 任何帮助都将不胜感激!?