【问题标题】:Why is implicit conversion not ambiguous for non-primitive types?为什么隐式转换对于非原始类型不模棱两可?
【发布时间】:2019-08-10 10:53:15
【问题描述】:

给定一个带有多个隐式转换函数(非显式构造函数和转换运算符)的简单类模板,如下例所示:

template<class T>
class Foo
{
private:
    T m_value;

public:
    Foo();

    Foo(const T& value):
        m_value(value)
    {
    }

    operator T() const {
        return m_value;
    }

    bool operator==(const Foo<T>& other) const {
        return m_value == other.m_value;
    }
};

struct Bar
{
    bool m;

    bool operator==(const Bar& other) const {
        return false;
    }
};

int main(int argc, char *argv[])
{
    Foo<bool> a (true);
    bool b = false;
    if(a == b) {
        // This is ambiguous
    }

    Foo<int> c (1);
    int d = 2;
    if(c == d) {
        // This is ambiguous
    }

    Foo<Bar> e (Bar{true});
    Bar f = {false};
    if(e == f) {
        // This is not ambiguous. Why?
    }
}

涉及原始类型的比较运算符(boolint)是模棱两可的,正如预期的那样 - 编译器不知道它是否应该使用转换运算符将左侧模板类实例转换为原始类型或使用转换构造函数将右侧的原始类型转换为预期的类模板实例。

然而,最后一个比较,涉及一个简单的struct,并不模棱两可。为什么?将使用哪个转换函数?

使用编译器 msvc 15.9.7 测试。

【问题讨论】:

  • explicit 关键字是个好东西。你应该研究一下。
  • e == f 在 C++20 中将是模棱两可的,因为它的价值。

标签: c++ templates c++17 implicit-conversion ambiguous


【解决方案1】:

根据[over.binary]/1

因此,对于任何二元运算符@x@y 都可以被解释 x.operator@(y)operator@(x,y)

根据这条规则,对于e == f,编译器只能将其解释为e.operator==(f),而不能解释为f.operator==(e)。所以没有歧义;您定义为Bar 成员的operator== 根本不适合重载解决方案。

a == bc == d 的情况下,内置候选operator==(int, int)(参见[over.built]/13)与定义为Foo&lt;T&gt; 成员的operator== 竞争。

【讨论】:

  • 您对第一句话的措辞似乎暗示切换操作数也会导致歧义,事实并非如此。
  • @Rakete1111 为什么它似乎暗示了这一点?
  • 我不是本地人,但如果你说“不是……”,则意味着……会模棱两可
【解决方案2】:

作为成员函数实现的运算符重载不允许隐式转换其左侧操作数,即调用它们的对象。

写出对运算符重载的显式调用总是有助于更好地理解它的作用:

Foo<Bar> e (Bar{true});
Bar f = {false};

// Pretty explicit: call the member function Foo<Bar>::operator==
if(e.operator ==(f)) { /* ... */ }

这不能与Bar 中的比较运算符混淆,因为它需要对左侧进行隐式转换,这是不可能的。

当您定义Bar 及其比较运算符时,您可以触发类似于您在内置类型中看到的歧义,如下所示:

struct Bar { bool m; };

// A free function allows conversion, this will be ambiguous:
bool operator==(const Bar&, const Bar&)
{
   return false;
}

这在Scott Meyers's Effective C++,第 24 条中得到了很好的演示和解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 2014-01-26
    • 2020-11-21
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多