简体   繁体   English

为什么隐式转换对非原始类型不明确?

[英]Why is implicit conversion not ambiguous for non-primitive types?

Given a simple class template with multiple implicit conversion functions (non-explicit constructor and conversion operator), as in the following example: 给定一个带有多个隐式转换函数的简单类模板(非显式构造函数和转换运算符),如下例所示:

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?
    }
}

The comparison operators involving primitive types ( bool , int ) are ambiguous, as expected - the compiler does not know whether it should use the conversion operator to convert the left-hand template class instance to a primitive type or use the conversion constructor to convert the right-hand primitive type to the expected class template instance. 涉及原始类型( boolint )的比较运算符是不明确的,正如预期的那样 - 编译器不知道是否应该使用转换运算符将左侧模板类实例转换为基本类型或使用转换构造函数转换右手原始类型到期望的类模板实例。

However, the last comparison, involving a simple struct , is not ambiguous. 但是,涉及简单struct的最后一次比较并不含糊。 Why? 为什么? Which conversion function will be used? 将使用哪种转换功能?

Tested with compiler msvc 15.9.7. 使用编译器msvc 15.9.7进行测试。

According to [over.binary]/1 根据[over.binary] / 1

Thus, for any binary operator @ , x@y can be interpreted as either x.operator@(y) or operator@(x,y) . 因此,对于任何二元运算符@x@y可以解释为x.operator@(y)operator@(x,y)

According to this rule, in the case of e == f , the compiler can only interpret it as e.operator==(f) , not as f.operator==(e) . 根据这个规则,在e == f的情况下,编译器只能将其解释为e.operator==(f) ,而不是f.operator==(e) So there is no ambiguity; 所以没有歧义; the operator== you defined as a member of Bar is simply not a candidate for overload resolution. operator==您定义为Bar的成员根本不是重载决策的候选者。

In the case of a == b and c == d , the built-in candidate operator==(int, int) (see [over.built]/13) competes with the operator== defined as a member of Foo<T> . a == bc == d的情况下,内置候选operator==(int, int) (参见[over.built] / 13)与operator==竞争operator==定义为Foo<T>的成员Foo<T>

Operator overloads implemented as member functions don't allow for implicit conversion of their left-hand operand, which is the object on which they are called. 作为成员函数实现的运算符重载不允许对其左侧操作数进行隐式转换,左侧操作数是调用它们的对象。

It always helps to write out the explicit call of an operator overload to better understand exactly what it does: 写出运算符重载的显式调用总是有助于更好地理解它的作用:

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

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

This can't be confused with the comparison operator in Bar , because it would require an implicit conversion of the left-hand side, which is impossible. 这不能与Bar的比较运算符混淆,因为它需要左侧的隐式转换,这是不可能的。

You can trigger an ambiguity similar to the ones you see with the built-in types when you define Bar and its comparison operator like this: 当您定义Bar及其比较运算符时,您可以触发类似于您使用内置类型看到的歧义:

struct Bar { bool m; };

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

This is nicely demonstrated and explained in Scott Meyers's Effective C++ , Item 24. 这在Scott Meyers的Effective C ++ ,第24项中得到了很好的证明和解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM