【问题标题】:what cause the ambiguous overload in gcc?是什么导致 gcc 中的模棱两可的过载?
【发布时间】:2022-01-25 23:20:20
【问题描述】:
#include <type_traits>
#include <iostream>

template<typename T>
struct Wrapper {
    T value;
    operator T&() & { std::cout << "call const ref" << std::endl; return this->value; }
    operator const T&() const& { std::cout << "call const ref" << std::endl; return this->value; }
    operator T&&() && { std::cout << "call move" << std::endl; return std::move(this->value); }
    operator const T&() const&& = delete;
    operator T&&() & = delete;
    operator T&&() const& = delete;
};

class A {
  public:
        A& operator=(const A&) { std::cout << "use copy" << std::endl; return *this; }
        A& operator=(A&&) { std::cout << "use move" << std::endl; return *this; }
};

int main() {
    Wrapper<A> b;
    A bb;
    bb = std::move(b);
}

我用gcc10.2编译了这段代码,得到如下错误

test.cc: In function ‘int main()’:
test.cc:24:21: error: ambiguous overload for ‘operator=’ (operand types are ‘A’ and ‘std::remove_reference<Wrapper<A>&>::type’ {aka ‘Wrapper<A>’})
   24 |     bb = std::move(b);
      |                     ^
test.cc:17:12: note: candidate: ‘A& A::operator=(const A&)’
   17 |         A& operator=(const A&) { std::cout << "use copy" << std::endl; return *this; }
      |            ^~~~~~~~
test.cc:18:12: note: candidate: ‘A& A::operator=(A&&)’
   18 |         A& operator=(A&&) { std::cout << "use move" << std::endl; return *this; }
      |            ^~~~~~~~

但我在 cppinsights.io 中用 clang 尝试了相同的代码,并且编译成功。 link

那么,是什么导致了 gcc 和 clang 之间的差异? 以及如何更改Wrapper 来修复它?

https://godbolt.org/z/37dPqafGK

【问题讨论】:

标签: c++ templates language-lawyer ambiguous


【解决方案1】:

看起来问题在于您有两个重载。有A::operator= 的重载解析,但在转换序列中也有Wrapper&lt;A&gt; 转换运算符的重载解析。 C++ 不能同时解决多个重载。

对于更简单的情况,想象一下如果A::operator=intfloat 重载,并且Wrapper&lt;A&gt; 定义了operator intoperator float

当然,只有当存在重载时才会出现这种情况,即Wrapper&lt;A&gt; 中有多个候选转换运算符。但是我看不出为什么 clang 应该排除 3 个转换运算符中的 2 个。

我也没有看到明显的解决方法。这个问题本身在我看来是模棱两可的。

【讨论】:

  • 感谢您的回答。在我看来,在调用 std::move 之后,它必须是左值。我不知道为什么左值可以强制转换为 const 右值以匹配另一个 A::operator=.
  • @YanyuPeng:不,std::move 的目的是产生一个 xvalue。这就是为什么它可以被移出。 xvalue 既是右值又是左值。
  • A aa; bb = std::move(aa); 为什么这段代码没问题,如果点是std::move
  • @YanyuPeng:这是一个重载:调用的函数是A::operator=,参数是A&amp;&amp; xvalue。最好的转换顺序是完全不转换。
猜你喜欢
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-01
相关资源
最近更新 更多