【问题标题】:How to create array of classes containing a constructor with reference argument?如何创建包含带有引用参数的构造函数的类数组?
【发布时间】:2021-12-07 16:56:07
【问题描述】:

我有一段代码,它给了我以下错误:

test.cpp:15:38: error: could not convert ‘std::ref<boost::asio::io_context>(((container*)this)->container::ioCtxt)’ from ‘std::reference_wrapper<boost::asio::io_context>’ to ‘A’
   15 |     std::array<A,2> bObjs = {std::ref(this->ioCtxt), nullptr};
      |                              ~~~~~~~~^~~~~~~~~~~~~~
      |                                      |
      |                                      std::reference_wrapper<boost::asio::io_context>
test.cpp:15:61: error: could not convert ‘nullptr’ from ‘std::nullptr_t’ to ‘A’
   15 |     std::array<A,2> bObjs = {std::ref(this->ioCtxt), nullptr};
      |                                                             ^
      |                                                             |
      |       

这是产生相关错误的最小代码段。这段最小的代码是对更复杂情况的简单表示。

#include <boost/asio.hpp>


struct A
{
    boost::asio::ip::tcp::socket sock;
    A(boost::asio::io_context& ioCtxtFromContainer): sock(ioCtxtFromContainer){}
};

struct container
{
    boost::asio::io_service ioCtxt;

    std::array<A,2> bObjs = {std::ref(this->ioCtxt), nullptr};
};

int main(void)
{
    container containerObj;

    return 0;
}

将引用传递给 A 的构造函数的正确方法是什么?此处不允许/不可能使用向量或其他形式的动态内存分配。

【问题讨论】:

  • 我认为你不能使用数组。您可以使用 vector 和 emplace 来代替,也可以使用单个变量成员。
  • @MarcStevens 更新了我的帖子。此处不允许使用向量或任何其他类型的动态内存分配。
  • 你试过没有std::ref吗?
  • @SergeyKolesnik nullptr 仍然是问题。
  • 这里开头std::ref的目的是什么?

标签: c++ boost-asio


【解决方案1】:
  1. 编译器无法通过初始化列表进行隐式转换:
#include <functional>
#include <array>

struct from{};

struct a
{
    a(from&){}
};

int main()
{
    from arg{};
    // std::array<a, 1> ar{std::ref(arg)}; // can't deduce from initializer list
    std::array<a, 1> ar{ arg }; // alright
    std::array<a, 1> ar2{ a(arg) }; // also alright
}
  1. 您希望如何从一个指针初始化一些需要引用的东西?
A(boost::asio::io_context& ioCtxtFromContainer):

您存储的是 对象 数组,而不是指针数组。所以,要么为A 提供一个构造函数,它接受一个指针(这不是你想要的),或者有一个指针数组:std::array&lt;A*, 2&gt;(最好使用智能指针)。
或者您可以使用 std::optional,就像 alanger 建议的那样。


您可以使用可变参数模板包装您的数组的初始化列表:

template <typename ... Args>
std::array<a, sizeof...(Args)> init_array(Args &&... args)
{
    return {a(std::forward<Args>(args))...};
}
    
from arg{};
auto ar3 = init_array(arg, std::ref(arg)); // works

【讨论】:

  • >> 你希望如何从一个指针初始化一些需要引用的东西?godbolt.org/z/anTEe4o4o 所以我会希望这也能在这里工作。不知道你在说什么......
  • 我说的是std::array&lt;A, 2&gt; 的第二个元素(它是一个对象 的数组),您正尝试通过nullptr 对其进行初始化。跨度>
  • 另外,bObjs = { a, b } ; 是来自initializer list 的初始化。它需要 A 类的对象或其他东西,可用于通过不超过一个用户定义的转换构造 A 的对象。 A &lt;- asio::io_context&amp; 是一种隐含的“转换”。 A &lt;- asio::io_context&amp; &lt;- std::reference_wrapper&lt;asio::io_context&amp;&gt; - 两次转换。初始化器列表无法推断出A 是如何从引用以外的东西构造出来的。而std::reference_wrapper 不是引用,它是一个带有转换运算符的包装器
  • 顺便说一句,仔细阅读你的godbolt链接中的错误。它不会因为你想象的其他原因编译
  • 好的,所以我仔细重新阅读了您的答案和cmets。关于这一点: >>std::array ar{ arg };
【解决方案2】:

如果您需要明确的空字段,请存储可选数组。

#include <iostream>
#include <optional>
#include <array>


auto main() -> int
{
    std::array<std::optional<double>, 3> x {3.2, std::nullopt, 5.0};
    return 0;
}

编辑: 或 C++17 之前的版本

#include <iostream>
#include <array>
#include <boost/asio.hpp>
#include <boost/optional.hpp>


struct A
{
    boost::asio::ip::tcp::socket sock;
    A(boost::asio::io_context& ioCtxtFromContainer): sock(ioCtxtFromContainer){}
};

struct container
{
    boost::asio::io_service ioCtxt;

    std::array<boost::optional<A>,2> bObjs = {
        A{this->ioCtxt}, boost::none};
};

auto main() -> int
{
    container containerObj;
    return 0;
}

https://godbolt.org/z/f9fhr5dnK

【讨论】:

  • 想详细说明您为什么选择std::optional?我尝试在网上阅读它,但我不太清楚为什么这里需要它
  • @ostrich525 来自您的代码,他只是假设您希望数组中的某些元素“未初始化”。因此,std::optional 是最简单且无开销的方法。
  • @ostrich525 除了将对象放入数组之外,我并不完全确定您想要什么,但这个nullptr(请参阅您的原始帖子)建议还需要某种“空”标记,因为动态分配(调整数组大小)不可用。 Optional 只是标准、流行和轻量级的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-17
  • 1970-01-01
  • 2014-02-25
  • 2022-01-22
  • 2011-10-05
相关资源
最近更新 更多