草庐IT

c++ - 将参数传递给 "array-like"容器构造函数

coder 2024-02-25 原文

背景

我正在使用具有以下限制的嵌入式平台:

  • 没有堆
  • 没有 Boost 库
  • C++11 得到支持

我过去曾多次处理过以下问题:

Create an array of class type T, where T has no default constructor

该项目最近才添加了 C++11 支持,到目前为止,每次我不得不处理这个问题时,我都在使用临时解决方案。既然 C++11 可用,我想我会尝试制定一个更通用的解决方案。

解决方案尝试

我复制了an example of std::aligned_storage为我的数组类型提出框架。结果如下所示:

#include <type_traits>

template<class T, size_t N>
class Array {
  // Provide aligned storage for N objects of type T
  typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];

public:
  // Build N objects of type T in the aligned storage using default CTORs
  Array()
  {
    for(auto index = 0; index < N; ++index)
      new(data + index) T();
  }

  const T& operator[](size_t pos) const
  {
    return *reinterpret_cast<const T*>(data + pos);
  }

  // Other methods consistent with std::array API go here
};

这是一个基本类型 - Array<T,N>仅在 T 时编译是默认可构造的。我对模板参数打包不是很熟悉,但查看一些示例使我得出以下结论:

template<typename ...Args>
Array(Args&&... args) 
{
  for(auto index = 0; index < N; ++index)
    new(data + index) T(args...);
}

这绝对是朝着正确方向迈出的一步。 Array<T,N>如果传递的参数与 T 的构造函数匹配,现在编译.

我唯一剩下的问题是构建一个 Array<T,N>数组中的不同元素具有不同的构造函数参数。我想我可以将其分为两种情况:

1 - 用户指定参数

这是我对 CTOR 的看法:

template<typename U>
Array(std::initializer_list<U> initializers)
{
  // Need to handle mismatch in size between arg and array
  size_t index = 0;
  for(auto arg : initializers) {
    new(data + index) T(arg);
    index++;
  }
}

除了需要处理数组和初始值设定项列表之间的维度不匹配之外,这似乎工作正常,但有许多方法可以处理不重要的问题。这是一个例子:

struct Foo {
  explicit Foo(int i) {}
};

void bar() {
  // foos[0] == Foo(0)
  // foos[1] == Foo(1)
  // ..etc
  Array<Foo,10> foos {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
}

2 - 参数遵循模式

在我之前的例子中,foos使用递增列表初始化,类似于 std::iota .理想情况下,我想支持如下内容,其中 range(int)返回可以初始化数组的东西。

// One of these should initialize foos with parameters returned by range(10)
Array<Foo,10> foosA = range(10);
Array<Foo,10> foosB {range(10)};
Array<Foo,10> foosC = {range(10)};
Array<Foo,10> foosD(range(10));

谷歌搜索显示 std::initializer_list不是“普通”容器,所以我认为我没有办法制作 range(int)返回 std::initializer_list取决于函数参数。

同样,这里有几个选项:

  • 运行时指定的参数(函数返回?)
  • 编译时指定的参数(constexpr 函数返回?模板?)

问题

  1. 到目前为止,此解决方案是否存在任何问题?
  2. 有人建议生成构造函数参数吗?除了硬编码 std::initializer_list 之外,我想不出在运行时或编译时的解决方案。 , 所以欢迎任何想法。

最佳答案

如果我正确理解您的问题,我也偶然发现了 std::array 在元素构造方面完全不灵活以支持聚合初始化(以及缺少具有灵活元素构造选项的静态分配容器)。我想出的最佳方法是创建一个自定义的类似数组的容器,它接受迭代器 来构造它的元素。 这是完全灵活的解决方案:

  • 适用于固定大小和动态大小的容器
  • 可以将不同或相同的参数传递给元素构造函数
  • 可以使用一个或多个(元组分段构造)参数调用构造函数,甚至可以为不同的元素调用不同的构造函数(控制反转)

以你的例子为例:

const size_t SIZE = 10;

std::array<int, SIZE> params;
for (size_t c = 0; c < SIZE; c++) {
    params[c] = c;
}

Array<Foo, SIZE> foos(iterator_construct, &params[0]); //iterator_construct is a special tag to call specific constructor
// also, we are able to pass a pointer as iterator, since it has both increment and dereference operators

注意:您可以通过使用自定义迭代器类完全跳过此处的参数数组分配,该类根据它的位置动态计算它的值。

对于多参数的构造器来说:

const size_t SIZE = 10;

std::array<std::tuple<int, float>, SIZE> params; // will call Foo(int, float)
for (size_t c = 0; c < SIZE; c++) {
    params[c] = std::make_tuple(c, 1.0f);
}

Array<Foo, SIZE> foos(iterator_construct, piecewise_construct, &params[0]);

具体的实现示例是一段很大的代码,所以除了总体思路之外,如果您还想深入了解实现细节,请告诉我 - 届时我会更新我的答案。

关于c++ - 将参数传递给 "array-like"容器构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39155418/

有关c++ - 将参数传递给 "array-like"容器构造函数的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby - 在 Ruby 中实现 `call_user_func_array` - 2

    我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)

  4. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  5. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  6. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  7. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  8. Ruby Koans about_array_assignment - 非平行与平行分配歧视 - 2

    通过ruby​​koans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John

  9. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  10. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

随机推荐