Ali
Ali

Reputation: 318

vector of references and ability to resize

The following code is similar to this answer Why can't I make a vector of references?

class A 
{
public:
    A(int x) : _x(x) 
    {
        std::cout << "A : ctor\n";
    }
    
    void func() 
    {
        std::cout << "I am func \n";
    }

    int getval()
    {
        return _x;
    }

private: 
    int _x;
};

int main() 
{
    A a1(2);
    A a2(3);

    std::vector<std::reference_wrapper<A>> vec;
    vec.push_back(std::ref(a1));
    vec.push_back(std::ref(a2));
    
    for(auto v : vec)
    {
        std::remove_reference<A&>::type(v).func();      
        std::cout << std::remove_reference<A&>::type(v).getval() << "\n";
    }             
}

I need to be able to resize vec (e.g. vec.resize(100)) and have something like

vec[n] = std::ref(b);

but I'll get this error which I don't quite understand:

/usr/include/c++/7/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::reference_wrapper<A>; _Args = {}]’:
/usr/include/c++/7/bits/stl_uninitialized.h:527:18:   required from ‘static _ForwardIterator std::__uninitialized_default_n_1<_TrivialValueType>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = std::reference_wrapper<A>*; _Size = long unsigned int; bool _TrivialValueType = false]’
/usr/include/c++/7/bits/stl_uninitialized.h:583:20:   required from ‘_ForwardIterator std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator = std::reference_wrapper<A>*; _Size = long unsigned int]’
/usr/include/c++/7/bits/stl_uninitialized.h:645:44:   required from ‘_ForwardIterator std::__uninitialized_default_n_a(_ForwardIterator, _Size, std::allocator<_Tp>&) [with _ForwardIterator = std::reference_wrapper<A>*; _Size = long unsigned int; _Tp = std::reference_wrapper<A>]’
/usr/include/c++/7/bits/vector.tcc:563:35:   required from ‘void std::vector<_Tp, _Alloc>::_M_default_append(std::vector<_Tp, _Alloc>::size_type) [with _Tp = std::reference_wrapper<A>; _Alloc = std::allocator<std::reference_wrapper<A> >; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/7/bits/stl_vector.h:692:21:   required from ‘void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = std::reference_wrapper<A>; _Alloc = std::allocator<std::reference_wrapper<A> >; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
<span class="error_line" onclick="ide.gotoLine('main.cpp',47)">main.cpp:47:19</span>:   required from here
/usr/include/c++/7/bits/stl_construct.h:75:7: error: no matching function for call to ‘std::reference_wrapper::reference_wrapper()’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/shared_ptr_base.h:56:0,
                 from /usr/include/c++/7/bits/shared_ptr.h:52,
                 from /usr/include/c++/7/memory:81,
                 from main.cpp:5:
/usr/include/c++/7/bits/refwrap.h:340:7: note: candidate: constexpr std::reference_wrapper<_Tp>::reference_wrapper(const std::reference_wrapper<_Tp>&) [with _Tp = A]
       reference_wrapper(const reference_wrapper&) = default;
       ^~~~~~~~~~~~~~~~~
/usr/include/c++/7/bits/refwrap.h:340:7: note:   candidate expects 1 argument, 0 provided
/usr/include/c++/7/bits/refwrap.h:334:7: note: candidate: std::reference_wrapper<_Tp>::reference_wrapper(_Tp&) [with _Tp = A]
       reference_wrapper(_Tp& __indata) noexcept
       ^~~~~~~~~~~~~~~~~
/usr/include/c++/7/bits/refwrap.h:334:7: note:   candidate expects 1 argument, 0 provided

Is there a way to have this capability for the given example?

Thanks

Upvotes: 2

Views: 360

Answers (1)

Quimby
Quimby

Reputation: 19113

error: no matching function for call to ‘std::reference_wrapper::reference_wrapper()’

That says wrapper's default constructor was not found. It does not have one because references must always be initialized.

std::vector<T>::resize uses this default constructor to initialize new elements. Think about it, what should this print?

std::vector<std::reference_wrapper<A>> vec;
vec.resize(100); # There now must be 100 valid elements.
std::cout << vec[50].get().getval();

If you want default semantics, use pointers.

If you call resize as an optimization, just use reserve+push_back.

Upvotes: 3

Related Questions