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 からクラス Mistake への型変換が必要なため、コンパイラが何をインスタンス化するかを判断できないと思われますが、テンプレートをまったく使用しない以外に、この問題を修正する方法がわかりません。

ちなみに、クラス内で演算子をフレンドとして定義してもうまくいきません。

ありがとう!

4

3 に答える 3

10

他の人があなたの問題に対する可能な解決策を提案していますが、何が起こっているのか、そしてなぜあなたの期待に応えられないのかを指摘したいと思います.

ここでの問題は、型推定を実行するときにユーザー定義の変換が考慮されないことです。コンパイラに次の式が表示された場合:

a + b

aとの両方bがタイプXであり、 の次の署名operator +:

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

コンパイラが最初に行うことはT、演算子のパラメーターの型が引数の型と正確に一致するよう試行して推測することです。これが不可能な場合、コンパイラは変換コンストラクターの可能性を考慮せずにすぐにあきらめ、他の候補関数 (または関数テンプレート) に焦点を当てます。

上記の状況を考慮すると、選択したもの( is not 、is notなど) を正確Mistake<T>にする方法がないことは明らかです。したがって、置換は失敗し、他の候補がないため、コンパイラーは呼び出しを解決する方法を知りません。 XTMistake<int>XMistake<X>X

一方、これがある場合:

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

上記は関数テンプレートではないため、関連する型推論はありません。したがって、コンパイラ呼び出しを解決しようとするときにユーザー定義の変換を考慮に入れ、Mistake<int>を受け入れるコンストラクターがあるため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 に答える