Consider I have a class A that is neither copy constructible nor copy assignable, but has any-like constructor A(auto &&). Can I create copies of std::vector<A> then?
#include <concepts>
#include <vector>
struct A {
A() {}
A(const A&) = delete;
A(auto &&) {}
A & operator=(const A&) = delete;
};
static_assert(!std::copy_constructible<A>);
const std::vector<A> v(3);
auto w( v ); // fails only in libstdc++
In GCC with libstdc++ the compilation fails with rather long error message, where the essential part seems to be:
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
90 | static_assert(is_constructible<_ValueType, _Tp>::value,
| ^~~~~
However, both MSVC and Clang with libc++ accept the program just fine. Online demo: https://gcc.godbolt.org/z/vhdEGn5sv
Which implementation is correct here?
auto w( v ) is exactly the condition in [container.reqmts]:
Preconditions: T is Cpp17CopyInsertable into X
which means that:
the following expression is well-formed:
allocator_traits<A>::construct(m, p, v)
In the extant case, m is an allocator of type std::allocator<A>, p is a pointer of type A*, and v is an expression that denotes an lvalue of type A or const A or an rvalue of type const A.
This is equivalent to:
::new (voidify(*p)) A(v) // when v is lvalue of type A or const A
This fails when v is an lvalue of type const A, so the precondition is violated, so the program has undefined behavior and anything is valid.
In practice, the standard library has license to construct from A& or const A& and they make different choices. Constructing from A& will by overload resolution choose the greedy template.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With