【问题标题】:Why is this call to the overloaded function ambiguous?为什么这个对重载函数的调用不明确?
【发布时间】:2020-06-14 05:30:32
【问题描述】:

考虑这个程序-

#include <string>
#include <vector>
#include <set>
void fun(const std::string& val) {
}

void fun(std::vector<std::string> val) {
}

int main()
{
    std::set<std::string> example;
    fun({std::begin(example), std::end(example)});
}

在编译时,我遇到了这些错误-

prog.cc: In function 'int main()':
prog.cc:13:49: error: call of overloaded 'fun(<brace-enclosed initializer list>)' is ambiguous
   13 |     fun({std::begin(example), std::end(example)});
      |                                                 ^
prog.cc:4:6: note: candidate: 'void fun(const string&)'
    4 | void fun(const std::string& val) {
      |      ^~~
prog.cc:7:6: note: candidate: 'void fun(std::vector<std::__cxx11::basic_string<char> >)'
    7 | void fun(std::vector<std::string> val) {
      |      ^~~

我知道std::string 有一个构造函数重载,它像这样接收initializer_list -

basic_string( std::initializer_list<char> ilist,
              const Allocator& alloc = Allocator() );

std::vector&lt;std::string&gt; 有一个看起来像这样的重载-

vector( std::initializer_list<std::string> init,
        const Allocator& alloc = Allocator() );

因此,很明显这两种方法的类型不同。一个接受initializer_listchar 和另一个std::string 类型。

在我的代码中,当我传递字符串的初始值设定项列表时,我将 2 个迭代器传递给一组字符串。

即便如此,为什么编译器会将此标记为模棱两可的调用?

【问题讨论】:

  • "在我的代码中,当我传递字符串的初始化列表时,我将 2 个迭代器传递给一组字符串。" 不,您的初始化列表有两个迭代器;它不是字符串列表。
  • 你知道你没有一个std::string的初始化列表,而是std::set&lt;std::string&gt;::const_iterator吗?
  • 此外,它实际上不是 std::initializer_list 除非 & 直到它实际上是初始化表达式绑定的内容。例如如果TT(std::set&lt;std::string&gt;::const_iterator, std::set&lt;std::string&gt;::const_iterator,则任何void fun(T) 都将起作用。或者在给定一些转换链的情况下等效的东西......
  • @MooingDuck const_ 来自哪里?

标签: c++ templates iterator overloading initializer-list


【解决方案1】:

编译器看到对以下两个构造函数的不明确调用(请注意,它们都没有使用初始化列表):

template <class InputIt>
std::vector::vector (InputIt first, InputIt last, const Allocator& alloc = Allocator());

template <class InputIt>
std::string::string (InputIt first, InputIt last, const Allocator& alloc = Allocator());

现在,如果您要使用这些迭代器参数实际调用 std::string 构造函数,您会得到一个错误,因为它们不会取消对 char 的引用。但由于该检查不是函数声明的一部分(例如通过 SFINAE),因此您会收到歧义错误。

【讨论】:

  • 有趣。但是编译错误(上面写着call of overloaded 'fun(&lt;brace-enclosed initializer list&gt;)' 的部分)似乎表明编译器已将其推断为initializer list。我猜这个初始化列表和std::initializer_list&gt;不一样?
  • 你用的是微软的编译器吗?当编译器感到困惑时,我将其视为 goto 消息。
  • 另外,编译器错误表明{begin(), end()} 被视为一个参数。为什么要尝试与至少采用 2 个参数的构造函数匹配?
  • @lakeweb 不,GCC 10 和 C++14
  • @PavanManjunath 那是因为它是一个字面的“初始化器列表”来初始化某些东西(可能是也可能不是std::initializer_list,例如,这里它是一个向量或字符串),它没有' 还没有被解析为一个类型,所以这就是编译器所能说的。就像std::vector&lt;std::string&gt;{5, "abc"} 不调用std::initializer_list 构造函数一样,但它仍然使用大括号封闭初始化列表(带有2 个参数)进行初始化。
猜你喜欢
  • 2016-05-18
  • 2014-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-18
  • 1970-01-01
相关资源
最近更新 更多