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: 24 [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<int> s1 = { 1, 2 }; // ok
>     std::set<int> s2 = { 1 }; // ok
>     std::set<int> 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<char>, my_allocator<char>>;

This (which I understand is currently a valid explicit instantiation of `std::basic_string`) will break if `std::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 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.

> 1. Change class template `basic_string` synopsis, 23.4.3 [basic.string] p5 as indicated:

>    >     basic_string() : basic_string(Allocator()) {}
>    >     explicit basic_string(const Allocator& a = Allocator());

> 2. Change 23.4.3.3 [string.cons] before p1 as indicated:

>    >     explicit basic_string(const Allocator& a = Allocator());

> 3. Change class template `deque` synopsis, 24.3.8.1 [deque.overview] p2 as indicated:

>    >     deque() : deque(Allocator()) {}
>    >     explicit deque(const Allocator& = Allocator());

> 4. Change 24.3.8.2 [deque.cons] before p1 as indicated:

>    >     explicit deque(const Allocator& = Allocator());

> 5. Change class template `forward_list` synopsis, [forwardlist.overview] p3 as indicated:

>    >     forward_list() : forward_list(Allocator()) {}
>    >     explicit forward_list(const Allocator& = Allocator());

> 6. Change [forwardlist.cons] before p1 as indicated:

>    >     explicit forward_list(const Allocator& = Allocator());

> 7. Change class template `list` synopsis, 24.3.10.1 [list.overview] p2 as indicated:

>    >     list() : list(Allocator()) {}
>    >     explicit list(const Allocator& = Allocator());

> 8. Change 24.3.10.2 [list.cons] before p1 as indicated:

>    >     explicit list(const Allocator& = Allocator());

> 9. Change class template `vector` synopsis, 24.3.11.1 [vector.overview] p2 as indicated:

>    >     vector() : vector(Allocator()) {}
>    >     explicit vector(const Allocator& = Allocator());

> 10. Change 24.3.11.2 [vector.cons] before p1 as indicated:

>     >     explicit vector(const Allocator& = Allocator());

> 11. Change class template specialization `vector<bool>` synopsis, 24.3.12 [vector.bool] p1 as indicated:

>     >     vector() : vector(Allocator()) {}
>     >     explicit vector(const Allocator& = Allocator());

> 12. Change class template `map` synopsis, 24.4.4.1 [map.overview] p2 as indicated:

>     >     map() : map(Compare()) {}
>     >     explicit map(const Compare& comp = Compare(),
>     >                  const Allocator& = Allocator());

> 13. Change 24.4.4.2 [map.cons] before p1 as indicated:

>     >     explicit map(const Compare& comp = Compare(),
>     >                  const Allocator& = Allocator());

> 14. Change class template `multimap` synopsis, 24.4.5.1 [multimap.overview] p2 as indicated:

>     >     multimap() : multimap(Compare()) {}
>     >     explicit multimap(const Compare& comp = Compare(),
>     >                       const Allocator& = Allocator());

> 15. Change 24.4.5.2 [multimap.cons] before p1 as indicated:

>     >     explicit multimap(const Compare& comp = Compare(),
>     >                       const Allocator& = Allocator());

> 16. Change class template `set` synopsis, 24.4.6.1 [set.overview] p2 as indicated:

>     >     set() : set(Compare()) {}
>     >     explicit set(const Compare& comp = Compare(),
>     >                  const Allocator& = Allocator());

> 17. Change 24.4.6.2 [set.cons] before p1 as indicated:

>     >     explicit set(const Compare& comp = Compare(),
>     >                  const Allocator& = Allocator());

> 18. Change class template `multiset` synopsis, 24.4.7.1 [multiset.overview] p2 as indicated:

>     >     multiset() : multiset(Compare()) {}
>     >     explicit multiset(const Compare& comp = Compare(),
>     >                       const Allocator& = Allocator());

> 19. Change 24.4.7.2 [multiset.cons] before p1 as indicated:

>     >     explicit multiset(const Compare& comp = Compare(),
>     >                       const Allocator& = Allocator());

> 20. Change class template `unordered_map` synopsis, 24.5.4.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());

> 21. Change 24.5.4.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());

> 22. Change class template `unordered_multimap` synopsis, 24.5.5.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());

> 23. Change 24.5.5.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());

> 24. Change class template `unordered_set` synopsis, 24.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());

> 25. Change 24.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());

> 26. Change class template `unordered_multiset` synopsis, 24.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());

> 27. Change 24.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.

1. Change class template `basic_string` synopsis, 23.4.3 [basic.string] p5 as indicated:

   >     basic_string() : basic_string(Allocator()) { }
   >     explicit basic_string(const Allocator& a = Allocator());

2. Change 23.4.3.3 [string.cons] before p1 as indicated:

   >     explicit basic_string(const Allocator& a = Allocator());

3. Change class template `deque` synopsis, 24.3.8.1 [deque.overview] p2 as indicated:

   >     deque() : deque(Allocator()) { }
   >     explicit deque(const Allocator& = Allocator());

4. Change 24.3.8.2 [deque.cons] before p1 as indicated:

   >     explicit deque(const Allocator& = Allocator());

5. Change class template `forward_list` synopsis, [forwardlist.overview] p3 as indicated:

   >     forward_list() : forward_list(Allocator()) { }
   >     explicit forward_list(const Allocator& = Allocator());

6. Change [forwardlist.cons] before p1 as indicated:

   >     explicit forward_list(const Allocator& = Allocator());

7. Change class template `list` synopsis, 24.3.10.1 [list.overview] p2 as indicated:

   >     list() : list(Allocator()) { }
   >     explicit list(const Allocator& = Allocator());

8. Change 24.3.10.2 [list.cons] before p1 as indicated:

   >     explicit list(const Allocator& = Allocator());

9. Change class template `vector` synopsis, 24.3.11.1 [vector.overview] p2 as indicated:

   >     vector() : vector(Allocator()) { }
   >     explicit vector(const Allocator& = Allocator());

10. Change 24.3.11.2 [vector.cons] before p1 as indicated:

    >     explicit vector(const Allocator& = Allocator());

11. Change class template specialization `vector<bool>` synopsis, 24.3.12 [vector.bool] p1 as indicated:

    >     vector() : vector(Allocator()) { }
    >     explicit vector(const Allocator& = Allocator());

12. Change class template `map` synopsis, 24.4.4.1 [map.overview] p2 as indicated:

    >     map() : map(Compare()) { }
    >     explicit map(const Compare& comp = Compare(),
    >                  const Allocator& = Allocator());

13. Change 24.4.4.2 [map.cons] before p1 as indicated:

    >     explicit map(const Compare& comp = Compare(),
    >                  const Allocator& = Allocator());

14. Change class template `multimap` synopsis, 24.4.5.1 [multimap.overview] p2 as indicated:

    >     multimap() : multimap(Compare()) { }
    >     explicit multimap(const Compare& comp = Compare(),
    >                       const Allocator& = Allocator());

15. Change 24.4.5.2 [multimap.cons] before p1 as indicated:

    >     explicit multimap(const Compare& comp = Compare(),
    >                       const Allocator& = Allocator());

16. Change class template `set` synopsis, 24.4.6.1 [set.overview] p2 as indicated:

    >     set() : set(Compare()) { }
    >     explicit set(const Compare& comp = Compare(),
    >                  const Allocator& = Allocator());

17. Change 24.4.6.2 [set.cons] before p1 as indicated:

    >     explicit set(const Compare& comp = Compare(),
    >                  const Allocator& = Allocator());

18. Change class template `multiset` synopsis, 24.4.7.1 [multiset.overview] p2 as indicated:

    >     multiset() : multiset(Compare()) { }
    >     explicit multiset(const Compare& comp = Compare(),
    >                       const Allocator& = Allocator());

19. Change 24.4.7.2 [multiset.cons] before p1 as indicated:

    >     explicit multiset(const Compare& comp = Compare(),
    >                       const Allocator& = Allocator());

20. Change class template `unordered_map` synopsis, 24.5.4.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());

21. Change 24.5.4.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_map` using 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 template `unordered_multimap` synopsis, 24.5.5.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 24.5.5.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_multimap` using 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 template `unordered_set` synopsis, 24.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 24.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_set` using 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 template `unordered_multiset` synopsis, 24.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 24.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_multiset` using 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.