テンプレートクラスの演算子+オーバーロードの戻り値の型


8

テンプレート化されたnumクラスを構築しようとしています。このクラスには、valタイプがのパブリック属性が必要Tです。これは、唯一のテンプレートパラメータです。さらに、値を提供する場合は、属性(val)をこの値で初期化する必要があります。これを行うには、次のコードを作成しました。

#include <iostream>

template<class T>
class Num {
public: 
    T val;

    Num():val(0) { std::cout<<"default constr used"<<std::endl; }
    Num(T value):val(value) {std::cout<<"constr (T value) used"<<std::endl; }
    ~Num() { std::cout<<"destructor used"<<std::endl; }

    template<typename U>
    Num operator+(const Num<U>& other) {
        return val+other.value;
    }
};

さらにmain()、次のようなプログラムをテストする関数を作成しました。

int main() {
    std::cout << Num<int>(1) + Num<double>(2.0);
    return 0;
}

しかし、プログラムの結果は今3です。それが3.0(タイプのdouble)であることを期待したのに対し。


現在コードを記述しているときにdoubleにする場合は、これらのオペランドを反転する必要があります。タイプの値を返すと宣言しNum<int>(1) + Num<double>(2.0);たものと同じNum<int>(1).operator+(Num<double>(2.0))ですNum<int>
scohe001

1
これはそのままではコンパイルできません。
Ted Lyngmo

コンパイルエラーが発生するのはなぜですか?
ファンカルロスラミレス

3
@JuanCarlosRamirezクラスにはという名前のメンバー変数がないためvalue
Ted Lyngmo

あなたは正しい、それを見なかった。
ファンカルロスラミレス

回答:


10

そのためには、戻り値の型を変更する必要があります。

あなたのコードで:

// vvv---- Means Num<T>
   Num operator+(const Num<U>& other) {
       return val + other.val;
   }

実際、クラステンプレート内では、テンプレート引数なしでクラスの名前を入力できますNum<T>

追加自体のタイプに関係なく、関数は常に最初のオペラントのタイプを返します。

あなたが欲しいのは、追加からそのタイプを推測することです:

auto operator+(const Num<U>& other) -> Num<decltype(val + other.val)> {
    return val + other.val;
}

そうすれば、C ++演算子の規則に従って、常に適切な戻り値の型になります。


2
C ++ 14以降では、あなたは必要ありません-> Num<decltype(val + other.val)>
BЈовић

@BЈовић、彼はそれを必要としています。それ以外の場合、戻り値の型はでありdecltype(val + other.val)、ではありませんNum<decltype(val + other.val)>
19

@BЈовићC ++ 17では、戻り値の型の控除とクラステンプレート引数の控除を使用して返すNum{val + other.val}
Guillaume Racicot

9

operator+その引数に関して対称でなければなりません。この対称性を明示的にするには、メンバー関数ではなくフリー関数として実装することをお勧めします。

例(C ++ 14の戻り値型の控除を使用):

template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
    using R = decltype(std::declval<T>() + std::declval<U>());
    return Num<R>{x.val + y.val};
}

std::declval<T>()汎用性のためにありますかT、またはUデフォルトの構成可能でない場合、あるいはその両方です。タイプが内蔵されたものに限定されている場合は、同様にintしてdouble、それを置き換えることができますT{}T()

using R = decltype(T{} + U{});

C ++ 17のクラステンプレート引数の控除により、さらに簡略化できます。

template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
    return Num{x.val + y.val};
}

うわーauto、戻り値の型を削除できるとは思いもしませんでした。これはかなりクールです。
scohe001

@ scohe001、それはC ++ 14機能です。
19
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.