Parsing compilation error: no matching function for call to 'std::pair<,>::pair()'

早过忘川 提交于 2020-04-18 05:29:22

问题


This is a followup question to assigning-of-unordered-map-to-pair-of-objects. This is a question about the interpretation of the compiler errors (and not a repeat question, as that question was already fully answered). I was asked whether I took a look at the errors, and to post the errors so that others might benefit from an understanding. This is the first error for this:

#include <bits/stdc++.h>
using namespace std;

struct foo {
  int n;
  foo(int n): n(n) {};
  // foo(): n(0) {};
};
int main(){
  unordered_map<int, pair<foo,foo>> m;
  m[3] = make_pair(foo(1),foo(2));
}

And here is the first error after compilation (rest omitted for now):

g++ -std=c++17 -Weffc++ -Wall -Wextra -Wsign-conversion  pairs.cpp -o ../build/pairs.bin
In file included from /usr/include/c++/8/functional:54,
                 from /usr/include/x86_64-linux-gnu/c++/8/bits/stdc++.h:71,
                 from pairs.cpp:1:
/usr/include/c++/8/tuple: In instantiation of ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {int&&}; long unsigned int ..._Indexes1 = {0}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = const int; _T2 = std::pair<foo, foo>]’:
/usr/include/c++/8/tuple:1657:63:   required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {int&&}; _Args2 = {}; _T1 = const int; _T2 = std::pair<foo, foo>]’
/usr/include/c++/8/ext/new_allocator.h:136:4:   required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const int, std::pair<foo, foo> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Tp = std::__detail::_Hash_node<std::pair<const int, std::pair<foo, foo> >, false>]’
/usr/include/c++/8/bits/alloc_traits.h:475:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const int, std::pair<foo, foo> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Tp = std::__detail::_Hash_node<std::pair<const int, std::pair<foo, foo> >, false>; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::__detail::_Hash_node<std::pair<const int, std::pair<foo, foo> >, false> >]’
/usr/include/c++/8/bits/hashtable_policy.h:2093:36:   required from ‘std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type* std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _NodeAlloc = std::allocator<std::__detail::_Hash_node<std::pair<const int, std::pair<foo, foo> >, false> >; std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type = std::__detail::_Hash_node<std::pair<const int, std::pair<foo, foo> >, false>]’
/usr/include/c++/8/bits/hashtable_policy.h:736:8:   required from ‘std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type& std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type&&) [with _Key = int; _Pair = std::pair<const int, std::pair<foo, foo> >; _Alloc = std::allocator<std::pair<const int, std::pair<foo, foo> > >; _Equal = std::equal_to<int>; _H1 = std::hash<int>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type = std::pair<foo, foo>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type = int]’
/usr/include/c++/8/bits/unordered_map.h:978:20:   required from ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type&&) [with _Key = int; _Tp = std::pair<foo, foo>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, std::pair<foo, foo> > >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = std::pair<foo, foo>; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = int]’
pairs.cpp:11:6:   required from here
/usr/include/c++/8/tuple:1668:70: error: no matching function for call to ‘std::pair<foo, foo>::pair()’
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)

回答1:


The library code is trying to default construct a pair of foo (that's what std::pair<foo, foo>::pair() in the last line means). But it can't do that because foo doesn't have a default constructor.

All the library templates make certain requirements on the types used to parameterise them. It seems std::unordered_map requires a default constructor.

I have a feeling (but I'm not going to look it up) that you could avoid this problem if you didn't use operator[] to insert into your map (in other words it's operator[] that needs the default constructor). If this is a problem try using emplace instead.

m.emplace(3, make_pair(foo(1),foo(2)));



回答2:


std::unordered_map::operator[] needs to default construct new element. If you class is not default constructible, you can't use operator[] to create new element and then assign to it.

Use emplace or insert or insert_or_assign to insert new element into a map.




回答3:


In general try to read these error message backwards.

1. Look at the last line (broken up to fit better on the available space)

/usr/include/c++/8/tuple:1668:70: error: no matching function for call
         to ‘std::pair<foo, foo>::pair()’
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)

This tells you immediately what's going on: There is a call somewhere (we'll have to find out where it originates), to a function that doesn't exist. That function is called

std::pair<foo, foo>::pair()

This is a constructor of a type from the standard library. Specifically it is a constructor without arguments.

2. So let's have a look at the documentation for pair. Oddly enough, there seems to be a constructor without arguments there.

3. Why doesn't it exist? Let's read on in the documentation:

1) Default constructor. Value-initializes both elements of the pair, first and second.
This constructor participates in overload resolution if and only if std::is_default_constructible_v<first_type> and std::is_default_constructible_v<second_type> are both true. This constructor is explicit if and only if either first_type or second_type is not implicitly default-constructible.

(emphasis mine)

4. Great let's check the condition, first_type and second_type are both the type foo in this case. Let's examine this type:

struct foo {
  int n;
  foo(int n): n(n) {};
  // foo(): n(0) {};
};

There is a foo(int) constructor for this type, and a commented out foo() constructor. There should be an implicit default constructor, right? No:

If no user-declared constructors of any kind are provided for a class type (struct, class, or union), the compiler will always declare a default constructor as an inline public member of its class.

We have a foo(int), hence the compiler does not generate foo() on its own. Aha, the call fails because indeed the function does not exist.

5. Okay, but why is it called in the first place? I don't remember calling such a function. -> Look at the "next" line in your error:

pairs.cpp:11:6:   required from here

That line (line 11 in pairs.cpp) reads:

m[3] = make_pair(foo(1),foo(2));

6. What does the documentation have to say about the first function called there? std::unordered_map<int,std::pair<foo,foo>>::operator[]:

Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist. ... When the default allocator is used, this results in the key being copy constructed from key and the mapped value being value-initialized.

7. What does value-initialisation mean?

T()     (1)     
new T ()    (2)     
Class::Class(...) : member() { ... }    (3)     
T object {};    (4)     (since C++11)
T{}     (5)     (since C++11)
new T {}    (6)     (since C++11)
Class::Class(...) : member{} { ... }    (7)     (since C++11)

Remember, T here is the value_type of your unordered_map, which in turn is pair<foo,foo>. That looks suspiciously like the call the compiler couldn't find earlier.

8. If we want to use std::unordered_map<K,T>::operator[], T better be value initialisable, e.g. by providing a T::T() constructor. That's where we have to fix it.

Conclusion

Read the error meticulously, check out the documentation for stuff you don't already know and follow up on the requirements of the functions you are using. And remember to read the error message backwards to figure out where the error was encountered, and in which of your own files it was triggered. Then examine that line.



来源:https://stackoverflow.com/questions/60776989/parsing-compilation-error-no-matching-function-for-call-to-stdpair-pair

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!