Home > Blockchain >  How to create array of classes containing a constructor with reference argument?
How to create array of classes containing a constructor with reference argument?

Time:12-08

I have the piece of code hereunder which gives me the following errors:

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};
      |                                                             ^
      |                                                             |
      |       

This is the minimal piece of code which creates the error in question. This minimal piece of code is a simplistic representation of a more complex situation.

#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;
}

What is the correct way of passing a reference to A's constructor? Using vectors or an other form of dynamic memory allocation is not allowed/possible here.

CodePudding user response:

  1. Conmpiler can't do implicit conversion via initializer list:
#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. How do you expect to initialize from a Pointer something, that takes a reference?
A(boost::asio::io_context& ioCtxtFromContainer):

You store an array of objects, not an array of pointers. So, either provide a constructor for A which takes a pointer (which is not what you pbviously want), or have an array of pointers: std::array<A*, 2> (using smart pointers preferrably).
Or you can use std::optional, like alanger has suggested.


You can wrapp your initializer list for your array with a variadic template:

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

CodePudding user response:

Store array of optionals if you need explicitly empty fields.

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


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

EDIT: or pre-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

  • Related