13

这对于那里的 C++ 大师来说。

考虑以下代码:

class X { };

template <class T>
class Mistake {
public:
  T x;

  Mistake(const T& k) : x(k) { }
  Mistake(const X&) : x(1) { }

  void print() { cout << x << endl; }
};

template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b)
{
  return Mistake<T>(a.x + b.x);
}

我有一个类“错误”,我想对其进行加法操作。当我尝试:

X a, b;
Mistake<int> foo = a + b;

我得到一个编译错误;编译器似乎无法意识到必须实例化模板 operator+。

另一方面,如果我之前添加了以下代码:

Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)
{
  return Mistake<int>(a.x + b.x);
}

那么一切都很好。有人知道为什么吗?我怀疑编译器无法弄清楚要实例化什么,因为需要从类 X 到类错误的类型转换,但我不知道如何解决这个问题,除非根本不使用模板。

顺便说一句,将类中的操作员定义为友元也行不通。

谢谢!

4

3 回答 3

10

虽然其他人已经为您的问题提出了可能的解决方案,但我想指出发生了什么,以及为什么无法满足您的期望。

这里的问题是执行类型推导时不考虑用户定义的转换。当编译器出现这个表达式时:

a + b

其中ab都是 类型X, 以及 的以下签名operator +

template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b)

编译器要做的第一件事是尝试和推断T,以使运算符的参数类型与参数的类型完全匹配。如果这不可能,编译器立即放弃,不考虑可能的转换构造函数,并专注于其他候选函数(或函数模板)。

考虑到上述情况,很明显,无论您选择什么(is not 、is not等) ,都无法使 exacltyMistake<T>成为exaclty 。 因此,替换失败并且编译器不知道如何解决调用,因为周围没有其他候选者。XTMistake<int>XMistake<X>X

另一方面,当你有这个时:

Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)

不涉及类型推导,因为上面不是函数模板。因此,编译器在尝试解析调用时考虑用户定义的转换,并且由于Mistake<int>有一个接受 a 的构造函数X,因此上述operator +被认为是可行的候选者,并被选中。

于 2013-05-10T19:00:01.940 回答
3

我不认为有办法。你能达到的最纯粹的是

Mistake<int> foo = static_cast<Mistake<int>>(a) + static_cast<Mistake<int>>(b);

或者,如果您使用与非对称操作数类型匹配的附加重载稍微推动它:

template <class T, class U>
Mistake<T> operator+(const Mistake<T>& a, U const& b) {
    return a + static_cast<Mistake<T>>(b);
}

    // and later:
    foo = Mistake<int>(a) + b;

完整的现场演示:http: //ideone.com/ki14GO

#include <iostream>

class X { };

template <class T>
class Mistake {
    public:
        T x;

        Mistake(const T& k) : x(k) { }
        Mistake(const X&) : x(1) { }

        void print() { std::cout << x << std::endl; }
};

template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b) {
    return Mistake<T>(a.x + b.x);
}

template <class T, class U>
Mistake<T> operator+(const Mistake<T>& a, U const& b) {
    return a + static_cast<Mistake<T>>(b);
}

template <class T, class U>
Mistake<T> operator+(const U& a, Mistake<T> const& b) {
    return static_cast<Mistake<T>>(a) + b;
}

int main()
{
    X a, b;
    Mistake<int> foo = static_cast<Mistake<int>>(a) + static_cast<Mistake<int>>(b);
    foo = Mistake<int>(a) + b;
    foo = a + Mistake<int>(b);
}
于 2013-05-10T18:49:44.843 回答
1

我相信编译器在推断a + b.

您可以定义:

X operator+(const X & a, const  X & b) {
   return a /* ??? or something else */;
}

如果您有任何方法可以a + b根据X.

于 2013-05-10T18:54:14.600 回答