【问题标题】:error: call of overloaded distance is ambiguous错误:超载距离的调用不明确
【发布时间】:2018-08-31 20:13:59
【问题描述】:

我有一些代码(我没有编写,但正在尝试编译)--iostream_combo.cc--,这样做会给我以下错误:

./moses/moses/comboreduct/combo/iostream_combo.cc: In function ‘std::__cxx11::string opencog::combo::l2ph(const string&, const std::vector<std::__cxx11::basic_string<char> >&)’:
./moses/moses/comboreduct/combo/iostream_combo.cc:543:64: error: call of overloaded ‘distance(std::vector<std::__cxx11::basic_string<char> >::const_iterator, __gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >&)’ is ambiguous
             arity_t idx = distance(labels.begin(), found_it) + 1;
                                                            ^ In file included from /usr/include/c++/8/bits/stl_algobase.h:66,
             from /usr/include/c++/8/bits/char_traits.h:39,
             from /usr/include/c++/8/ios:40,
             from /usr/include/c++/8/ostream:38,
             from /usr/include/c++/8/iostream:39,
             from ./moses/moses/comboreduct/combo/iostream_combo.h:28,
             from ./moses/moses/comboreduct/combo/iostream_combo.cc:24:
/usr/include/c++/8/bits/stl_iterator_base_funcs.h:138:5: note: candidate: ‘typename std::iterator_traits<_Iterator>::difference_type std::distance(_InputIterator, _InputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; typename std::iterator_traits<_Iterator>::difference_type = long int]’
 distance(_InputIterator __first, _InputIterator __last)
 ^~~~~~~~ In file included from /usr/local/include/boost/range/distance.hpp:18,
             from /usr/local/include/boost/range/functions.hpp:21,
             from /usr/local/include/boost/range/iterator_range_core.hpp:38,
             from /usr/local/include/boost/lexical_cast.hpp:30,
             from ./moses/moses/comboreduct/combo/iostream_combo.h:30,
             from ./moses/moses/comboreduct/combo/iostream_combo.cc:24:
/usr/local/include/boost/iterator/distance.hpp:49:9: note: candidate: ‘constexpr typename boost::iterators::iterator_difference<Iterator>::type boost::iterators::distance_adl_barrier::distance(SinglePassIterator, SinglePassIterator) [with SinglePassIterator = __gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; typename boost::iterators::iterator_difference<Iterator>::type = long int]’
     distance(SinglePassIterator first, SinglePassIterator last)
     ^~~~~~~~

我使用的是 Ubuntu 16.04 x64、Boost 1.68 和 gcc 8.2。因此,重现问题的步骤如下:

  1. 在 Ubuntu 16.04 上
  2. 安装gcc-8
  3. 使用它从源代码构建 boost 1.68
  4. Git 克隆 moses repository 并按照那里的说明进行操作:基本上 1) git clone 并构建 cogutil; 2)尝试使mosescd buildcmake ..make

我足够了解 C++(我认为),我可以看到对 std::distance 的调用已超载。我没有看到消除歧义的方法,尽管我猜它必须包括对found_it 的一些重写或一些显式转换而不是auto

【问题讨论】:

  • 成为会员这么久,有这么多问题,你应该知道得更多。 Minimal, Complete, and Verifiable Example 在哪里?也许是时候刷新how to ask good questions了?当然也请阅读this question checklist
  • 抱歉,我认为问题仅取决于代码和语言,而不是其他细节。
  • 显式类型声明不是强制转换。 auto 确定性地推断出确切的类型,因此没有区别。 C++ 总是强类型的
  • 该文件有 600 多行,并且需要多个外部依赖项。请尝试将其复制到一个小于 50 行的小程序中。
  • @Barry 我也是这么想的,然后我就这么做了,只是确认了一个预感 :)

标签: c++ c++11 boost std ambiguous


【解决方案1】:

电话是这样的:

    arity_t idx = distance(labels.begin(), found_it) + 1;

这意味着 distance 是通过 ADL 找到的,因此会考虑所有关联的命名空间。如果例如,这可能会证明是有问题的。有两个命名空间为distance 提供同样适用的重载:

Live On Coliru

#include <iterator>
#include <vector>

namespace OyVeh {
    struct X { };

    template <typename It>
    size_t distance(It, It) { return 42; } // just to throw in a wrench
}

int main() {
    std::vector<OyVeh::X> v{3};

    auto f = v.begin();
    auto l = v.end();

    // now f and l have both `::std` and `::OyVeh` as associated namespaces. The following is ambiguous:

    return distance(f, l);
}

大致有两种方法可以解决:

  • 从关联的命名空间中删除模棱两可的 distance 声明(如果竞争者是 std::distanceboost::distance,这可能是不可能的)
  • 编辑调用以消除对 ADL 的依赖(例如,将它们限定为 std::distance(...) 或将它们括起来 (distance)(...)

显示解决方法:

Live On Coliru

{
    using OyVeh::distance;
    return (distance)(f, l); // parentheses suppress ADL
}

return std::distance(f, l); // also works, obviously
return OyVeh::distance(f, l); // but beware the meaning might change

【讨论】:

  • 谢谢,我不知道 ADL 有一个通用名称,这个答案促使我去研究它。
  • 事实证明,只需将distance 替换为std::distance 就足够了。这让我对答案犹豫不决——我应该将其标记为正确答案吗?
  • 是的。因为它解释了原因以及您最终使用的确切解决方法。当然要当心评论(尽管在这种情况下,std::distance 的语义似乎很明显是需要的)
猜你喜欢
  • 2021-01-07
  • 2021-11-02
  • 2018-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多