解析编译错误:没有匹配函数调用 'std::pair<,>::pair()'

Posted

技术标签:

【中文标题】解析编译错误:没有匹配函数调用 \'std::pair<,>::pair()\'【英文标题】:Parsing compilation error: no matching function for call to 'std::pair<,>::pair()'解析编译错误:没有匹配函数调用 'std::pair<,>::pair()' 【发布时间】:2020-03-20 15:24:54 【问题描述】:

这是assigning-of-unordered-map-to-pair-of-objects 的后续问题。这是一个关于编译器错误解释的问题(而不是重复的问题,因为该问题已经完全回答)。有人问我是否查看了错误,并发布错误,以便其他人可以从理解中受益。这是第一个错误:

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

【问题讨论】:

【参考方案1】:

通常尝试向后阅读这些错误消息。

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

这会立即告诉您发生了什么:somewhere(我们必须找出它的来源)调用了一个不存在的函数。该函数被调用

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

这是标准库中类型的构造函数。具体来说,它是一个没有参数的构造函数。

2. 那么让我们来看看documentation for pair。奇怪的是,那里似乎有一个没有参数的构造函数。

3. 为什么它不存在?让我们继续阅读文档:

1) 默认构造函数。值初始化该对的两个元素,第一个和第二个。 此构造函数参与重载决议当且仅当std::is_default_constructible_v&lt;first_type&gt;std::is_default_constructible_v&lt;second_type&gt; 都是真的。 当且仅当 first_type 或 second_type 不是隐式可默认构造的,此构造函数才是显式的。

(强调我的)

4. 好的,让我们检查一下条件,first_typesecond_type 在这种情况下都是 foo 类型。让我们检查一下这种类型:

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

此类型有一个foo(int) 构造函数,并有一个注释掉的foo() 构造函数。应该有一个隐式的默认构造函数,对吧? No:

如果没有为类提供任何用户声明的构造函数 类型(结构、类或联合),编译器将始终声明一个 默认构造函数作为其类的内联公共成员。

我们有一个foo(int),因此编译器不会自行生成foo()。啊哈,调用失败是因为函数确实不存在。

5. 好的,但为什么首先调用它?我不记得调用过这样的函数。 -> 查看错误中的“下一个”行:

pairs.cpp:11:6:   required from here

那一行(pairs.cpp 中的第 11 行)内容如下:

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

6. 文档对那里调用的第一个函数有什么看法? std::unordered_map&lt;int,std::pair&lt;foo,foo&gt;&gt;::operator[]:

返回对映射到等效键的值的引用 键,如果这样的键不存在,则执行插入。 ... 当使用默认分配器时,这会导致键被复制 由键和映射值value-initialized构成。

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 是您的unordered_mapvalue_type,而pair&lt;foo,foo&gt; 又是pair&lt;foo,foo&gt;。这看起来有点像编译器之前找不到的调用。

8. 如果我们想使用std::unordered_map&lt;K,T&gt;::operator[]T 最好是值可初始化,例如通过提供T::T() 构造函数。这就是我们必须解决的问题。

结论

仔细阅读错误,查看文档以了解您不知道的内容,并跟进您正在使用的功能的要求。并记住向后阅读错误消息以找出错误发生的位置,以及它是在您自己的哪个文件中触发的。然后检查那条线。

【讨论】:

-bitmask 非常感谢,感谢您一步一步的指导。【参考方案2】:

库代码试图默认构造foopair(这就是最后一行中的std::pair&lt;foo, foo&gt;::pair() 的含义)。但它不能这样做,因为foo 没有默认构造函数。

所有库模板都对用于参数化它们的类型提出了某些要求。看来std::unordered_map 需要一个默认构造函数。

我有一种感觉(但我不会查)如果您不使用 operator[] 插入到您的地图中,您可以避免这个问题(换句话说,需要 operator[]默认构造函数)。如果这是一个问题,请尝试改用emplace

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

【讨论】:

谢谢约翰,是的,这是链接问题给出的答案。我只是在思考如何破译最后一行,当我第一次看它时,我想,我是否需要实现一个函数 std::pair::pair(),因为没有匹配的函数发现...从那个错误中我不清楚它期待 foo 的默认构造函数。但是可能还有其他我忽略的线索...这个问题的重点实际上是如何解析此类错误。 (我使用了 m.insert -> 效果与 Kamil 指出的一样) 只需按照 LIFO 顺序进行诊断。在此示例中,最后的第二个错误是焦点提示。 -Red Wave,只要确保我理解你的建议,看看最后一个错误,然后是上面的那个,等等。这样做,我认为以 /usr/include/c++/ 开头的那个8/tuple:在实例化中 ... 告诉我它期待一个带有 _Args2 = 的 foo 构造函数,所以我必须一直走到第一行才能确定它期待一个零参数构造函数。它是否正确?看来您希望我专注于这一行:/usr/include/c++/8/bits/unordered_map.h:978:20: 这是最后一个错误(也许我的方向颠倒了)。 @Red.Wave 想想 pair 的默认构造函数必须做什么。显然它需要默认构造两个 f​​oo 对象,因此需要一个 foo 的默认构造函数。 我不为 C++ 的神秘诊断辩护。特别是在模板方面。在过去 15 年左右的时间里,“约束模板”一直是委员会中最古老和最大的挑战之一。 “概念”提案经过无数次修订,直到最终对 C++20 提出。 STL 实现在该方向上对齐需要大量时间。如果operator[] 受到适当的约束,那么早期和更易读的诊断就足够了。尽管级联错误消息仍然是一个由来已久的故事。【参考方案3】:

std::unordered_map::operator[] 需要默认构造新元素。如果您的类不是默认可构造的,则不能使用operator[] 创建新元素然后分配给它。

使用emplaceinsertinsert_or_assign 将新元素插入到地图中。

【讨论】:

以上是关于解析编译错误:没有匹配函数调用 'std::pair<,>::pair()'的主要内容,如果未能解决你的问题,请参考以下文章

错误:没有匹配的调用函数

C++ [错误] 没有匹配的调用函数

创建函数变体向量时出现“调用没有匹配函数”错误

犰狳错误:没有匹配函数调用‘inv(arma::SpMat<double>&)’

构造函数中的“没有匹配的函数调用”

没有匹配的成员函数调用 child.value