VS2017 provides the following error when I try to add a std::atomic
to a struct stored in an std::pair
(inside an std::unordered_map
):
error C2660: 'std::pair<uint32_t,AtomicStruct>::pair': function does not take 2 arguments
I've simplified the issue down to the following code (removing the std::unordered_map for clarity/focus):
#include <iostream> // std::cout
#include <utility> // std::pair
#include <atomic> // std::atomic
struct AtomicStruct
{
std::atomic_uint32_t a;
// associated data goes here...
};
using AtomicPair = std::pair<uint32_t, AtomicStruct>;
int main()
{
AtomicStruct as = { 1 }; // This initializer works just fine
std::cout << "as: " << as.a << std::endl; // Outputs "as: 1" as expected
AtomicPair pr1(0, as); // error C2660
AtomicPair pr2(0, { 1 }); // error C2660
return 0;
}
From what I've pieced together so far:
std::atomic
deletes the copy-constructor.std::pair
's template checks for the parameters being is_copy_constructible
, when the parameters specify the first
and second
of the std::pair.std::atomic
, or second, parameter isn't is_copy_constructible
, the constructor definition isn't created.std::pair(const std::pair&) = default
copy constructor, which fails because the number of parameters is incorrect (two, instead of one), as well as the type is wrong.If I remove the std::atomic
from the struct, I can put it directly into a std::pair
std::pair<uint32_t, std::atomic_uint32_t> pr3(0, 1); // Works!
I thought maybe the initializer was being used for construction too early, and also tried:
AtomicPair pr4(0, { { 1 } }); // error C2660
Maybe I'm missing something obvious... Does anyone know a way to store structs containing std::atomic
s in a std::pair
?
Since an answer, via link, was given in the comments, and I don't know how long that will live, I'm copy/pasting the crucial bits of the answer/example provided by @NathanOliver, in case someone else needs the answer.
As @Nichol_Bolas pointed out, my initial intent was for AtomicStruct
to be an aggregate; if anyone knows of a way to improve upon the answer below and keep AtomicStruct
as an aggregate, I'm open to suggestions.
struct AtomicStruct
{
std::atomic_uint32_t a;
AtomicStruct(uint32_t a) : a(a) {}
// associated data goes here...
};
int main()
{
//...
AtomicPair pr1{std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple(1)};
//...
}