Ошибка синтаксического анализа: нет подходящей функции для вызова 'std :: pair <,> :: pair ()' - PullRequest
0 голосов
/ 20 марта 2020

Это дополнительный вопрос к присваиванию неупорядоченной карты в пару объектов . Это вопрос о интерпретации ошибок компилятора (а не повторный вопрос, так как на этот вопрос уже был дан полный ответ). Меня спросили, посмотрел ли я на ошибки и опубликовал ли они ошибки, чтобы другие могли извлечь пользу из понимания. Это первая ошибка для этого:

#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));
}

А вот первая ошибка после компиляции (пока остальные опущены):

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))...)

Ответы [ 3 ]

1 голос
/ 20 марта 2020

Код библиотеки пытается создать по умолчанию pair из foo (это то, что означает std::pair<foo, foo>::pair() в последней строке). Но он не может этого сделать, потому что foo не имеет конструктора по умолчанию.

Все шаблоны библиотек предъявляют определенные требования к типам, используемым для их параметризации. Кажется, std::unordered_map требует конструктор по умолчанию.

У меня есть чувство (но я не собираюсь его искать), что вы могли бы избежать этой проблемы, если бы вы не использовали operator[] для вставки в ваша карта (другими словами это operator[], который нуждается в конструкторе по умолчанию). Если это проблема, попробуйте использовать emplace.

m.emplace(3, make_pair(foo(1),foo(2)));
0 голосов
/ 20 марта 2020

В общем, попробуйте прочитать это сообщение об ошибке в обратном порядке.

1. Посмотрите на последнюю строку (разбито, чтобы лучше соответствовать доступному пространству)

/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))...)

Это немедленно сообщает вам, что происходит: есть вызов где-то (мы должны выяснить, где он происходит), функции, которой не существует. Эта функция называется

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

Это конструктор типа из стандартной библиотеки. В частности, это конструктор без аргументов.

2. Итак, давайте посмотрим на документацию для пары . Как ни странно, там, кажется, есть конструктор без аргументов.

3. Почему его не существует? Давайте прочтем в документации:

1) Конструктор по умолчанию. Значение инициализирует оба элемента пары, первый и второй.
Этот конструктор участвует в разрешении перегрузки тогда и только тогда, когда std::is_default_constructible_v<first_type> и std::is_default_constructible_v<second_type> оба имеют значение true . Этот конструктор является явным тогда и только тогда, когда first_type или second_type неявно не конструируются по умолчанию.

(выделено мной)

4. Отлично, давайте проверим условие, first_type и second_type оба имеют тип foo в этом случае. Давайте рассмотрим этот тип:

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

Существует конструктор foo(int) для этого типа и закомментированный конструктор foo(). Должен быть неявный конструктор по умолчанию, верно? Нет:

Если для типа класса (типа, структуры, класса или класса) не предусмотрено никаких пользовательских конструкторов union), компилятор всегда объявляет конструктор по умолчанию как встроенный элемент publi c своего класса.

У нас есть foo(int), следовательно, компилятор не генерирует foo() на своем своя. Ага, вызов не удался, потому что действительно функция не существует.

5. Хорошо, но почему она вызывается в первую очередь? Я не помню, чтобы я вызывал такую ​​функцию. -> Посмотрите на следующую строку в вашей ошибке:

pairs.cpp:11:6:   required from here

Эта строка (строка 11 попарно. cpp) гласит:

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

6. Что документация должна сказать о первой вызываемой там функции? std::unordered_map<int,std::pair<foo,foo>>::operator[]:

Возвращает ссылку на значение, сопоставленное ключу, эквивалентному ключу, выполняет вставку, если такой ключ еще не существует . ... Когда используется распределитель по умолчанию, это приводит к тому, что ключ копируется из ключа и сопоставленное значение инициализированное значение .

7. Что означает инициализация значения?

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)

Помните, T - это value_type вашего unordered_map, который в свою очередь равен pair<foo,foo>. Это выглядит подозрительно, как вызов, который компилятор не смог найти ранее.

8. Если мы хотим использовать std::unordered_map<K,T>::operator[], T лучше быть инициализируемым значением, например, предоставляя T::T() конструктор. Вот где мы должны это исправить.

Заключение

Внимательно прочитайте ошибку, ознакомьтесь с документацией, которую вы еще не знаете, и выполните требования из функций, которые вы используете. И не забудьте прочитать сообщение об ошибке в обратном направлении, чтобы выяснить, где произошла ошибка и в каких ваших файлах она возникла. Затем изучите эту строку.

0 голосов
/ 20 марта 2020

std::unordered_map::operator[] необходимо по умолчанию построить новый элемент. Если ваш класс не является конструируемым по умолчанию, вы не можете использовать operator[] для создания нового элемента и затем присвоить ему.

Используйте emplace или insert или insert_or_assign для вставки нового элемента в карта.

...