テンプレート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
)であると期待していました。
そのためには、戻り値の型を変更する必要があります。
あなたのコードで:
// 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++演算子の規則に従って、常に正しい戻り型になります。
_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};
}
_
T
やU
がデフォルトで構築できない場合、std::declval<T>()
は genericity に存在します。型が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};
}
_