Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::map, std::unordered_map - narrowing conversion in initializer list

Tags:

c++

c++17

stdmap

Is it bug or standart permits it?

#include <iostream>
#include <map>
#include <unordered_map>

int main() {
    std::unordered_map<int,int> mm {{44,44}, {33.3, 54}, {222.2,222.2}};
    for(auto& [f,s] :mm) {
        std::cout<<f<<" - "<<s<<std::endl;
    }

    std::map<int,int> m {{44,44}, {33.3, 54}, {222.2,222.2}};
    for(auto& [f,s] :m) {
       std::cout<<f<<" - "<<s<<std::endl;
    }
}

Test it on wandbox.org with clang10 and gcc10. There is not such problem with std::set and std::unordered_set.

like image 240
AlexBG Avatar asked Jan 21 '20 08:01

AlexBG


1 Answers

The element type of std::map and std::unordered_map is std::pair. The problem is that std::pair has a templated constructor,

template< class U1, class U2 >
constexpr pair( U1&& x, U2&& y );

Initializes first with std::forward<U1>(x) and second with std::forward<U2>(y).

E.g. given {33.3, 54}, U1 is deduced as double and U2 is deduced as int, note that this is an exact match and no conversions are required for this constructor to be used to construct the std::pair, then no narrowing conversion happens either.

On the other hand, for std::set, given std::set<int> s {33.3};, the constructor of std::set taking std::initializer_list<int> will be used, and the std::initializer_list<int> is initialized from {33.3}, narrow conversion happens.

like image 134
songyuanyao Avatar answered Oct 28 '22 08:10

songyuanyao