g++ --version
yields:
g++.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 4.9.1
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Program:
#include <memory>
#include <type_traits>
#include <unordered_map>
static_assert(!std::is_copy_constructible<std::unordered_map<int,std::unique_ptr<int>>>::value,"Copyable");
int main () { }
Result of compilation:
.unorderedmapcopyable.cpp:5:1: error: static assertion failed: Copyable
static_assert(!std::is_copy_constructible<std::unordered_map<int,std::unique_ptr<int>>>::value,"Copyable");
^
Relevant standardese:
On Containers Being Copyable
For the statements X u(a)
and X u=a
to be valid, for some container type X
, which contains type T
, where a
is a value of type X
:
Requires:
T
isCopyInsertable
intoX
§23.2.1 [container.requirements.general]
My understanding of this: If T
(in our case std::pair<const int,std::unique_ptr<int>>
) is not CopyInsertable
into X
(in our case std::unordered_map<int,std::unique_ptr<int>>
), then X u(a)
and X u=a
are not well-formed.
On CopyInsertable
T
isCopyInsertable
intoX
means that, in addition toT
beingMoveInsertable
intoX
, the following expression is well-formed:
allocator_traits<A>::construct(m, p, v)
and its evaluation causes the following postcondition to hold: The value of
v
is unchanged and is equivalent to*p
.
My understanding of this: std::pair<const int,std::unique_ptr<int>>
is not CopyInsertable
, due to the fact std::unique_ptr<int>
is not copyable:
Each object of a type
U
instantiated from theunique_ptr
template specified in this subclause [...] is notCopyConstructible
norCopyAssignable
.§20.8.1 [unique.ptr]
And due to the fact that the copy constructor of std::pair<const int,std::unique_ptr<int>>
is defaulted:
pair(const pair&) = default;
§20.3.2 [pairs.pair]
And due to the fact that std::pair<const int,std::unique_ptr<int>>
has a member of type std::unique_ptr<int>
:
template <class T1, class T2> struct pair {
[...]
T2 second;
§20.3.2 [pairs.pair]
And due to the fact that defaulted copy constructors are deleted when it is not the case that all members of a type are CopyConstructible
:
A defaulted copy/move constructor for a class
X
is defined as deleted if X has:[...]
- a non-static data member of class type
M
(or array thereof) that cannot be copied/moved because overload resolution, as applied toM
’s corresponding constructor, results in [...] a function that is deleted [...]§12.8 [class.copy]
On std::is_copy_constructible
For a referenceable type
T
, the same result asis_constructible<T,const T&>::value
, otherwisefalse
.§20.10.4.3 [meta.unary.prop]
My understanding/reading of this: std::is_copy_constructible<std::unordered_map<int,std::unique_ptr<int>>
is the same as std::is_constructible<std::unordered_map<int,std::unique_ptr<int>,std::unordered_map<int,std::unique_ptr<int> &>
.
On std::is_constructible
Given the following function prototype:
template <class T> add_rvalue_reference_t<T> create() noexcept;
the predicate condition for a template specialization
is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would be well-formed for some invented variablet
:
T t(create<Args>()...);
§20.10.4.3 [meta.unary.prop]
My understanding of this: std::is_constructible<std::unordered_map<int,std::unique_ptr<int>>,std::unordered_map<int,std::unique_ptr<int> &>
ought to be std::false_type
, not std::true_type
, since X u(a)
is not well-formed.
My Question
Should the above code be accepted? Is this a GCC/libstdc++ bug, or is there something in the standard I'm missing?
I don't currently have access to Clang or MSVC++, otherwise I'd test on them.
See Question&Answers more detail:os