【问题标题】:Why is this call to swap() ambiguous?为什么这个对 swap() 的调用模棱两可?
【发布时间】:2016-03-08 15:22:50
【问题描述】:

下面的程序

#include <algorithm>
#include <utility>
#include <memory>

namespace my_namespace
{


template<class T>
void swap(T& a, T& b)
{
  T tmp = std::move(a);
  a = std::move(b);
  b = std::move(tmp);
}

template<class T, class Alloc = std::allocator<T>>
class foo {};

}

int main()
{
  my_namespace::foo<int> *a, *b;

  using my_namespace::swap;

  swap(a,b);

  return 0;
}

导致g++clang 在我的系统上发出以下编译器错误:

$ clang -std=c++11 swap_repro.cpp -I.
swap_repro.cpp:28:3: error: call to 'swap' is ambiguous
  swap(a,b);
  ^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/bits/algorithmfwd.h:571:5: note: candidate function [with _Tp = my_namespace::foo<int, std::allocator<int> > *]
    swap(_Tp&, _Tp&)
    ^
swap_repro.cpp:10:6: note: candidate function [with T = my_namespace::foo<int, std::allocator<int> > *]
void swap(T& a, T& b)
     ^
1 error generated.

$ g++ -std=c++11 swap_repro.cpp -I.
swap_repro.cpp: In function ‘int main()’:
swap_repro.cpp:28:11: error: call of overloaded ‘swap(my_namespace::foo<int>*&, my_namespace::foo<int>*&)’ is ambiguous
   swap(a,b);
           ^
swap_repro.cpp:28:11: note: candidates are:
swap_repro.cpp:10:6: note: void my_namespace::swap(T&, T&) [with T = my_namespace::foo<int>*]
 void swap(T& a, T& b)
      ^
In file included from /usr/include/c++/4.9/bits/stl_pair.h:59:0,
                 from /usr/include/c++/4.9/utility:70,
                 from /usr/include/c++/4.9/algorithm:60,
                 from swap_repro.cpp:1:
/usr/include/c++/4.9/bits/move.h:166:5: note: void std::swap(_Tp&, _Tp&) [with _Tp = my_namespace::foo<int>*]
     swap(_Tp& __a, _Tp& __b)
     ^

我不明白为什么std::swap 被视为候选过载,但这与foostd::allocator&lt;T&gt; 的使用有关。

去掉foo的第二个模板参数可以让程序编译不出错。

【问题讨论】:

    标签: c++ namespaces argument-dependent-lookup name-lookup class-template


    【解决方案1】:

    因为std::allocator&lt;T&gt; 用作模板类型参数,所以std 命名空间是ADL 的关联命名空间。

    [basic.lookup.argdep]/2,第 2 条,强调我的:

    此外,如果T 是一个类模板特化,它的关联 命名空间和类还包括:命名空间和类 与提供的模板参数的类型相关联 模板类型参数(不包括模板模板参数); 任何模板模板参数都是其成员的命名空间; 以及任何成员模板用作模板的类 模板参数是成员。

    ...和指针具有与其指向的类型相同的关联命名空间/类集:

    如果T 是指向U 的指针或U 的数组,则其关联的命名空间和 类是与U 关联的类。

    【讨论】:

      【解决方案2】:

      关联命名空间的集合是根据从参数类型中可见的各种类型确定的。值得注意的是,对于类模板,相关的命名空间包括所有模板参数的相关命名空间。使用参数相关查找查找不合格函数时,会搜索所有关联的命名空间。

      foo&lt;int&gt; 的模板参数列表实际上是foo&lt;int, std::allocator&lt;int&gt;&gt;,从而将命名空间std 拖到图片中,并且那里已经有swap() 的通用重载。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-21
        相关资源
        最近更新 更多