Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deduction guides for std::unordered_map in C++17

I have read about deduction guides for std::unordered_map in C++17 from using a cppreference.

Then tried to run following example, which is copied from cppreference.

#include <unordered_map>
int main() {
// std::unordered_map m1 = {{"foo", 1}, {"bar", 2}}; // Error: braced-init-list has no type
                                                     // cannot deduce pair<const Key, T> from
                                                     // {"foo", 1} or {"bar", 2}
   std::unordered_map m1 = std::initializer_list<
                        std::pair<char const* const, int>>({{"foo", 2}, {"bar", 3}}); // guide #2
   std::unordered_map m2(m1.begin(), m1.end()); // guide #1
}

But, the compiler gives an error.

main.cpp: In function 'int main()':
main.cpp:7:84: error: class template argument deduction failed:
                         std::pair<char const* const, int>>({{"foo", 2}, {"bar", 3}}); // guide #2
                                                                                    ^
main.cpp:7:84: error: no matching function for call to 'unordered_map(std::initializer_list<std::pair<const char* const, int> >)'
In file included from /usr/local/include/c++/7.2.0/unordered_map:48:0,
                 from main.cpp:1:
/usr/local/include/c++/7.2.0/bits/unordered_map.h:101:11: note: candidate: template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> unordered_map(std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>)-> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>
     class unordered_map
           ^~~~~~~~~~~~~

Why does compiler give an error?

like image 285
msc Avatar asked Sep 16 '17 08:09

msc


1 Answers

edit: I am updating this answer after discussing the issue with a developer of the GCC C++ library (libstdc++). The edited answer has more details, rational, and a future direction.

Technically this is a compiler bug in GCC, while clang sticks to the standard. The first guide in your code works with clang-6 -stdlib=libc++.

std::unordered_map m1 = std::initializer_list<
                        std::pair<char const* const, int>>({{"foo", 2}, {"bar", 3}}); // guide #2

So does

std::unordered_map m2{
std::pair<char const* const, int>{"foo", 2}, {"bar", 3}}; // guide #2

But GCC deviates from the standard and allows:

std::unordered_map m2{std::pair{"foo", 2}, {"bar", 3}};

Which is effectively the same as

// not const char*const, but rather const char*
std::unordered_map m2{std::pair<const char*, int>{"foo", 2}, {"bar", 3}};

This is not standard conforming, since the key part of the pair is supposed to be const. This is in fact better than the standard, because this deviation makes it possible to deduce the template parameters. This is in contrast to the standard guides makes it impossible to deduce std::unordered_map template parameters, without writing them explicitly, which is quite useless.

This issue is mentioned on the Library Working Group (LWG) page at Issue 3025: Map-like container deduction guides should use pair<Key, T>, not pair<const Key, T>. GCC simply decided to go with a nonconforming deduction guides, which make this feature useful, rather than sticking with usefulness standard-conforming guides.

Most likely, this issue will have an official DR soon, making GCC's implementation conform to the amended standard.

NOTE: You can read the details in the GCC bug report on this issue, for more details.

P.S. I hope you know what you are doing, making a key of type const char*.

like image 200
Michael Veksler Avatar answered Sep 22 '22 00:09

Michael Veksler