Issue 2193: Default constructors for standard library containers are explicit (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.
2193. Default constructors for standard library containers are explicit
Section: 23 [containers] Status: C++14 Submitter: Richard Smith Opened: 2012-10-04 Last modified: 2017-07-05
Priority: 1
View other active issues in [containers].
View all other issues in [containers].
View all issues with C++14 status.
Discussion:
Most (all?) of the standard library containers have explicit default constructors. Consequently:
std::set s1 = { 1, 2 }; // ok std::set s2 = { 1 }; // ok std::set s3 = {}; // ill-formed, copy-list-initialization selected an explicit constructor
Note that Clang + libc++ rejects the declaration of s3 for this reason. This cannot possibly match the intent.
Suggested fix: apply this transformation throughout the standard library:
set() : set(Compare()) {} explicit set(const Compare& comp
= Compare(), const Allocator& = Allocator());
[ 2012-10-06: Daniel adds concrete wording. ]
[2012, Portland: Move to Open]
This may be an issue better solved by a core language tweak. Throw the issue over to EWG and see whether they believe the issue is better resolved in Core or Library.
AJM suggest we spawn a new status of 'EWG' to handle such issues - and will move this issue appropriately when the software can record such resolutions.
[2013-08-27, Joaquín M López Muñoz comments:]
For the record, I'd like to point out that the resolution proposed by the submitter, namely replacing
explicit basic_string(const Allocator& a = Allocator());
by
basic_string() : basic_string(Allocator()) {} explicit basic_string(const Allocator& a);
(and similarly for other container and container-like classes) might introduce a potential backwards-compatibility problem related with explicit instantiation. Consider for instance
struct my_allocator { my_allocator(...); // no default ctor ... };
template class std::basic_string<char, std::char_traits, my_allocator>;
This (which I understand is currently a valid explicit instantiation of std::basic_string) will break ifstd::basic_string ctors are modified as proposed by this issue, since my_allocator doesn't have a default ctor.
[2013-10-06, Daniel comments:]
Issue 2303(i) describes the more general problem related to explicit instantiation requests in the current library and may help to solve this problem here as well.
[2014-02-13, Issaquah, Jonathan revises wording]
Previous resolution from Daniel [SUPERSEDED]:
This wording is relative to N3376.
The more general criterion for performing the suggested transformation was: Any type with an initializer-list constructor that also has an explicit default constructor.
- Change class template
basic_stringsynopsis, 27.4.3 [basic.string] p5 as indicated:basic_string() : basic_string(Allocator()) {}
explicit basic_string(const Allocator& a= Allocator());- Change 27.4.3.3 [string.cons] before p1 as indicated:
explicit basic_string(const Allocator& a
= Allocator());- Change class template
dequesynopsis, 23.3.5.1 [deque.overview] p2 as indicated:deque() : deque(Allocator()) {}
explicit deque(const Allocator&= Allocator());- Change 23.3.5.2 [deque.cons] before p1 as indicated:
explicit deque(const Allocator&
= Allocator());- Change class template
forward_listsynopsis, [forwardlist.overview] p3 as indicated:forward_list() : forward_list(Allocator()) {}
explicit forward_list(const Allocator&= Allocator());- Change [forwardlist.cons] before p1 as indicated:
explicit forward_list(const Allocator&
= Allocator());- Change class template
listsynopsis, 23.3.11.1 [list.overview] p2 as indicated:list() : list(Allocator()) {}
explicit list(const Allocator&= Allocator());- Change 23.3.11.2 [list.cons] before p1 as indicated:
explicit list(const Allocator&
= Allocator());- Change class template
vectorsynopsis, 23.3.13.1 [vector.overview] p2 as indicated:vector() : vector(Allocator()) {}
explicit vector(const Allocator&= Allocator());- Change 23.3.13.2 [vector.cons] before p1 as indicated:
explicit vector(const Allocator&
= Allocator());- Change class template specialization
vector<bool>synopsis, 23.3.14 [vector.bool] p1 as indicated:vector() : vector(Allocator()) {}
explicit vector(const Allocator&= Allocator());- Change class template
mapsynopsis, 23.4.3.1 [map.overview] p2 as indicated:map() : map(Compare()) {}
explicit map(const Compare& comp= Compare(),
const Allocator& = Allocator());- Change 23.4.3.2 [map.cons] before p1 as indicated:
explicit map(const Compare& comp
= Compare(),
const Allocator& = Allocator());- Change class template
multimapsynopsis, 23.4.4.1 [multimap.overview] p2 as indicated:multimap() : multimap(Compare()) {}
explicit multimap(const Compare& comp= Compare(),
const Allocator& = Allocator());- Change 23.4.4.2 [multimap.cons] before p1 as indicated:
explicit multimap(const Compare& comp
= Compare(),
const Allocator& = Allocator());- Change class template
setsynopsis, 23.4.6.1 [set.overview] p2 as indicated:set() : set(Compare()) {}
explicit set(const Compare& comp= Compare(),
const Allocator& = Allocator());- Change 23.4.6.2 [set.cons] before p1 as indicated:
explicit set(const Compare& comp
= Compare(),
const Allocator& = Allocator());- Change class template
multisetsynopsis, 23.4.7.1 [multiset.overview] p2 as indicated:multiset() : multiset(Compare()) {}
explicit multiset(const Compare& comp= Compare(),
const Allocator& = Allocator());- Change 23.4.7.2 [multiset.cons] before p1 as indicated:
explicit multiset(const Compare& comp
= Compare(),
const Allocator& = Allocator());- Change class template
unordered_mapsynopsis, 23.5.3.1 [unord.map.overview] p3 as indicated:unordered_map() : unordered_map(see below) {}
explicit unordered_map(size_type n= see below,
const hasher& hf = hasher(),const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());
- Change 23.5.3.2 [unord.map.cnstr] before p1 as indicated:
unordered_map() : unordered_map(see below) {}
explicit unordered_map(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());- Change class template
unordered_multimapsynopsis, 23.5.4.1 [unord.multimap.overview] p3 as indicated:
unordered_multimap() : unordered_multimap(see below) {}
explicit unordered_multimap(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());- Change 23.5.4.2 [unord.multimap.cnstr] before p1 as indicated:
unordered_multimap() : unordered_multimap(see below) {}
explicit unordered_multimap(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());- Change class template
unordered_setsynopsis, 23.5.6.1 [unord.set.overview] p3 as indicated:
unordered_set() : unordered_set(see below) {}
explicit unordered_set(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());- Change 23.5.6.2 [unord.set.cnstr] before p1 as indicated:
unordered_set() : unordered_set(see below) {}
explicit unordered_set(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());- Change class template
unordered_multisetsynopsis, 23.5.7.1 [unord.multiset.overview] p3 as indicated:
unordered_multiset() : unordered_multiset(see below) {}
explicit unordered_multiset(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());- Change 23.5.7.2 [unord.multiset.cnstr] before p1 as indicated:
unordered_multiset() : unordered_multiset(see below) {}
explicit unordered_multiset(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
[Issaquah 2014-02-11: Move to Immediate after final review]
Proposed resolution:
This wording is relative to N3376.
The more general criterion for performing the suggested transformation was: Any type with an initializer-list constructor that also has an explicit default constructor.
- Change class template
basic_stringsynopsis, 27.4.3 [basic.string] p5 as indicated:basic_string() : basic_string(Allocator()) { }
explicit basic_string(const Allocator& a= Allocator()); - Change 27.4.3.3 [string.cons] before p1 as indicated:
explicit basic_string(const Allocator& a
= Allocator()); - Change class template
dequesynopsis, 23.3.5.1 [deque.overview] p2 as indicated:deque() : deque(Allocator()) { }
explicit deque(const Allocator&= Allocator()); - Change 23.3.5.2 [deque.cons] before p1 as indicated:
explicit deque(const Allocator&
= Allocator()); - Change class template
forward_listsynopsis, [forwardlist.overview] p3 as indicated:forward_list() : forward_list(Allocator()) { }
explicit forward_list(const Allocator&= Allocator()); - Change [forwardlist.cons] before p1 as indicated:
explicit forward_list(const Allocator&
= Allocator()); - Change class template
listsynopsis, 23.3.11.1 [list.overview] p2 as indicated:list() : list(Allocator()) { }
explicit list(const Allocator&= Allocator()); - Change 23.3.11.2 [list.cons] before p1 as indicated:
explicit list(const Allocator&
= Allocator()); - Change class template
vectorsynopsis, 23.3.13.1 [vector.overview] p2 as indicated:vector() : vector(Allocator()) { }
explicit vector(const Allocator&= Allocator()); - Change 23.3.13.2 [vector.cons] before p1 as indicated:
explicit vector(const Allocator&
= Allocator()); - Change class template specialization
vector<bool>synopsis, 23.3.14 [vector.bool] p1 as indicated:vector() : vector(Allocator()) { }
explicit vector(const Allocator&= Allocator()); - Change class template
mapsynopsis, 23.4.3.1 [map.overview] p2 as indicated:map() : map(Compare()) { }
explicit map(const Compare& comp= Compare(),
const Allocator& = Allocator()); - Change 23.4.3.2 [map.cons] before p1 as indicated:
explicit map(const Compare& comp
= Compare(),
const Allocator& = Allocator()); - Change class template
multimapsynopsis, 23.4.4.1 [multimap.overview] p2 as indicated:multimap() : multimap(Compare()) { }
explicit multimap(const Compare& comp= Compare(),
const Allocator& = Allocator()); - Change 23.4.4.2 [multimap.cons] before p1 as indicated:
explicit multimap(const Compare& comp
= Compare(),
const Allocator& = Allocator()); - Change class template
setsynopsis, 23.4.6.1 [set.overview] p2 as indicated:set() : set(Compare()) { }
explicit set(const Compare& comp= Compare(),
const Allocator& = Allocator()); - Change 23.4.6.2 [set.cons] before p1 as indicated:
explicit set(const Compare& comp
= Compare(),
const Allocator& = Allocator()); - Change class template
multisetsynopsis, 23.4.7.1 [multiset.overview] p2 as indicated:multiset() : multiset(Compare()) { }
explicit multiset(const Compare& comp= Compare(),
const Allocator& = Allocator()); - Change 23.4.7.2 [multiset.cons] before p1 as indicated:
explicit multiset(const Compare& comp
= Compare(),
const Allocator& = Allocator()); - Change class template
unordered_mapsynopsis, 23.5.3.1 [unord.map.overview] p3 as indicated:unordered_map();
explicit unordered_map(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());
- Change 23.5.3.2 [unord.map.cnstr] before p1 as indicated:
unordered_map() : unordered_map(size_type(see below)) { }
explicit unordered_map(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
unordered_mapusing the specified hash function, key equality func-
tion, and allocator, and using at least n buckets.If n is not provided,For the default constructor
the number of buckets is implementation-defined.max_load_factor()returns 1.0. 22. Change class templateunordered_multimapsynopsis, 23.5.4.1 [unord.multimap.overview] p3 as indicated:
unordered_multimap();
explicit unordered_multimap(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()); 23. Change 23.5.4.2 [unord.multimap.cnstr] before p1 as indicated:
unordered_multimap() : unordered_multimap(size_type(see below)) { }
explicit unordered_multimap(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
unordered_multimapusing the specified hash function, key equality
function, and allocator, and using at least n buckets.If n is not provided,For the default constructor
the number of buckets is implementation-defined.max_load_factor()returns 1.0. 24. Change class templateunordered_setsynopsis, 23.5.6.1 [unord.set.overview] p3 as indicated:
unordered_set();
explicit unordered_set(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()); 25. Change 23.5.6.2 [unord.set.cnstr] before p1 as indicated:
unordered_set() : unordered_set(size_type(see below)) { }
explicit unordered_set(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
unordered_setusing the specified hash function, key equality func-
tion, and allocator, and using at least n buckets.If n is not provided,For the default constructor
the number of buckets is implementation-defined.max_load_factor()returns 1.0. 26. Change class templateunordered_multisetsynopsis, 23.5.7.1 [unord.multiset.overview] p3 as indicated:
unordered_multiset();
explicit unordered_multiset(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()); 27. Change 23.5.7.2 [unord.multiset.cnstr] before p1 as indicated:
unordered_multiset() : unordered_multiset(size_type(see below)) { }
explicit unordered_multiset(size_type n= see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
unordered_multisetusing the specified hash function, key equality
function, and allocator, and using at least n buckets.If n is not provided,For the default constructor
the number of buckets is implementation-defined.max_load_factor()returns 1.0.