I have this code where I have a class MyElement
that holds a MyData<UnderlyingData>
that’s constructed during the constructor:
#include <atomic>
#include <iostream>
#include <vector>
struct UnderlyingData {
int a;
int b;
UnderlyingData(int _a, int _b) : a(_a), b(_b) {}
};
template <typename T> class MyData {
public:
std::atomic<T> data_;
template <typename... Args>
MyData(Args &&...args) : data_(T(std::forward<Args>(args)...)) {}
};
class MyElement {
public:
int c;
MyData<UnderlyingData> mydata;
explicit MyElement(int _c) : c(_c), mydata(0, 6) {}
};
int main() {
std::vector<MyElement> arr;
arr.emplace_back(5);
std::cout << arr.at(0).c << " " << arr.at(0).mydata.data_.load().a << " "
<< arr.at(0).mydata.data_.load().b << "\n";
return 0;
}
As you can see, MyData<UnderlyingData>
holds an atomic<UnderlyingData>
and the constructor of MyData
attempts to perfect forward to the UnderlyingData
through the atomic. This code works if I try to construct a MyData<UnderlyingData>
variable manually, or a MyElement
variable, like this:
MyElement element(5);
std::cout << element.c << " " << element.mydata.data_.load().b << "\n";
However, when I put MyElement
into a vector and use either emplace_back
or push_back(MyElement(5))
, I get this cryptic error:
test.cpp: In instantiation of ‘MyData<T>::MyData(Args&& ...) [with Args = {MyData<UnderlyingData>}; T = UnderlyingData]’:
test.cpp:20:7: required from ‘void std::_Construct(_Tp*, _Args&& ...) [with _Tp = MyElement; _Args = {MyElement}]’
/usr/include/c++/11/bits/stl_uninitialized.h:92:18: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<MyElement*>; _ForwardIterator = MyElement*; bool _TrivialValueTypes = false]’
/usr/include/c++/11/bits/stl_uninitialized.h:151:15: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<MyElement*>; _ForwardIterator = MyElement*]’
/usr/include/c++/11/bits/stl_uninitialized.h:333:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<MyElement*>; _ForwardIterator = MyElement*; _Tp = MyElement]’
/usr/include/c++/11/bits/stl_uninitialized.h:355:2: required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = MyElement*; _ForwardIterator = MyElement*; _Allocator = std::allocator<MyElement>]’
/usr/include/c++/11/bits/vector.tcc:474:3: required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {int}; _Tp = MyElement; _Alloc = std::allocator<MyElement>; std::vector<_Tp, _Alloc>::iterator = std::vector<MyElement>::iterator]’
/usr/include/c++/11/bits/vector.tcc:121:21: required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int}; _Tp = MyElement; _Alloc = std::allocator<MyElement>; std::vector<_Tp, _Alloc>::reference = MyElement&]’
test.cpp:30:19: required from here
test.cpp:17:34: error: no matching function for call to ‘UnderlyingData::UnderlyingData(MyData<UnderlyingData>)’
17 | MyData(Args &&...args) : data_(T(std::forward<Args>(args)...)) {}
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:9:3: note: candidate: ‘UnderlyingData::UnderlyingData(int, int)’
9 | UnderlyingData(int _a, int _b) : a(_a), b(_b) {}
| ^~~~~~~~~~~~~~
test.cpp:9:3: note: candidate expects 2 arguments, 1 provided
test.cpp:5:8: note: candidate: ‘constexpr UnderlyingData::UnderlyingData(const UnderlyingData&)’
5 | struct UnderlyingData {
| ^~~~~~~~~~~~~~
test.cpp:5:8: note: no known conversion for argument 1 from ‘MyData<UnderlyingData>’ to ‘const UnderlyingData&’
test.cpp:5:8: note: candidate: ‘constexpr UnderlyingData::UnderlyingData(UnderlyingData&&)’
test.cpp:5:8: note: no known conversion for argument 1 from ‘MyData<UnderlyingData>’ to ‘UnderlyingData&&’
I’ve tried a number of permutations and can’t seem to figure it out either. I don’t understand why the constructor inferred seems to be UnderlyingData::UnderlyingData(MyData<UnderlyingData>)
as I’m just passing two numbers to it… Any advice I can get is much appreciated.
Yeah. The alternative is to move to a deque instead of a vector (as deque doesnt require move or copy) which works for me as I don’t need random access, only fast insert and iteration.
I should try this with c++20 and how it does in error messages. Right now I’m on 17…