This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

### 3531. LWG 3025 broke previous valid code

Section: 24.4.4.1 [map.overview], 24.4.5.1 [multimap.overview], 24.5.4.1 [unord.map.overview], 24.5.5.1 [unord.multimap.overview] Status: New Submitter: Mike Spertus Opened: 2021-03-09 Last modified: 2021-04-20

Priority: 3

View all other issues in [map.overview].

View all issues with New status.

Discussion:

The resolution for LWG 3025 enabled code like the following to be accepted:

>     map m1{{pair{1, 2}, {3, 4}}, less<int>()};

but breaks code that had been previously working like the following

>     using value_type = pair<const int, int>;

>     map m2{{value_type{1, 2}, {3, 4}}, less<int>()};

as shown on godbolt.

[Acknowledgment to Tim Song and Arthur O'Dwyer for independently pointing out this case on the LWG mailing list]

[2021-04-20; Reflector poll]

Priority set to 3. Three preferences expressed for Option B, none for A.

Proposed resolution:

This wording is relative to N4878.

> We present two partial wording options for `std::map`, denoted by (A) and (B) below. If the committee accepts one of them, we will complete them to all key-value containers.

1. (A) Wording option 1: In this option, we restore the deduction guide that was removed in LWG 3025 while maintaining the one that was added, demonstrates this working.

   1. Modify 24.4.4.1 [map.overview] as indicated:

      >     […]
      >     template<class Key, class T, class Compare = less<Key>,
      >              class Allocator = allocator<pair<const Key, T>>>
      >       map(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
      >         -> map<Key, T, Compare, Allocator>;

      >     template<class Key, class T, class Compare = less<Key>,
      >              class Allocator = allocator<pair<const Key, T>>>
      >       map(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
      >         -> map<Key, T, Compare, Allocator>;

      >     template<class InputIterator, class Allocator>
      >       map(InputIterator, InputIterator, Allocator)
      >         -> map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
      >                less<iter-key-type<InputIterator>>, Allocator>;

      >     template<class Key, class T, class Allocator>
      >       map(initializer_list<pair<Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>;

      >     template<class Key, class T, class Allocator>
      >       map(initializer_list<pair<const Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>;
      >     […]

2. (B) Wording option 2: This one follows Tim Song's suggestion: "It seems that the cleanest fix is to 1) disallow the `initializer_list<value_type>` constructors from being used for CTAD, and 2) change the guides to use `remove_const_t<Key>`." This change has been tested locally with g++ similar to the above godbolt.

   1. Modify 24.4.4.1 [map.overview] as indicated:

      >     […]
      >     // types
      >     using key_type = Key;
      >     using mapped_type = T;
      >     using value_type = type_identity_t<pair<const Key, T>>;
      >     […]

      >     template<class Key, class T, class Compare = less<remove_const_t<Key>>,
      >              class Allocator = allocator<pair<const Key, T>>>
      >       map(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
      >         -> map<remove_const_t<Key>, T, Compare, Allocator>;

      >     template<class InputIterator, class Allocator>
      >       map(InputIterator, InputIterator, Allocator)
      >         -> map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
      >                less<iter-key-type<InputIterator>>, Allocator>;

      >     template<class Key, class T, class Allocator>
      >       map(initializer_list<pair<Key, T>>, Allocator)
      >         -> map<remove_const_t<Key>, T, less<remove_const_t<Key>>, Allocator>;

      >     […]