前回の「std::vectorを拡張してみた」のその後です。
色々な指摘を受けて検討した結果、以下のようにしてみました。
エイリアスとグローバル関数を定義することで、std::vector<double>
で四則演算やmean,sd,norm
が計算できるようにしてみました。範囲for文が直観的だったので採用。
my_vector.h
#include <vector>
#include <cmath>
using my_vector = std::vector<double>;
inline my_vector& operator+=(my_vector& lhs, const my_vector& rhs) {
for (std::size_t i = 0; i < lhs.size(); i++)
lhs[i] += rhs[i];
return lhs;
}
inline my_vector& operator-=(my_vector& lhs, const my_vector& rhs) {
for (std::size_t i = 0; i < lhs.size(); i++)
lhs[i] -= rhs[i];
return lhs;
}
inline my_vector& operator*=(my_vector& lhs, const my_vector& rhs) {
for (std::size_t i = 0; i < lhs.size(); i++)
lhs[i] *= rhs[i];
return lhs;
}
inline my_vector& operator/=(my_vector& lhs, const my_vector& rhs) {
for (std::size_t i = 0; i < lhs.size(); i++)
lhs[i] /= rhs[i];
return lhs;
}
inline my_vector& operator+=(my_vector& lhs, const double rhs) {
for (auto& e : lhs) e += rhs;
return lhs;
}
inline my_vector& operator-=(my_vector& lhs, const double rhs) {
for (auto& e : lhs) e -= rhs;
return lhs;
}
inline my_vector& operator*=(my_vector& lhs, const double rhs) {
for (auto& e : lhs) e *= rhs;
return lhs;
}
inline my_vector& operator/=(my_vector& lhs, const double rhs) {
for (auto& e : lhs) e /= rhs;
return lhs;
}
inline my_vector operator+(const my_vector& lhs, const my_vector& rhs) {
return my_vector(lhs) += rhs;
}
inline my_vector operator-(const my_vector& lhs, const my_vector& rhs) {
return my_vector(lhs) -= rhs;
}
inline my_vector operator*(const my_vector& lhs, const my_vector& rhs) {
return my_vector(lhs) *= rhs;
}
inline my_vector operator/(const my_vector& lhs, const my_vector& rhs) {
return my_vector(lhs) /= rhs;
}
inline my_vector operator+(const my_vector& lhs, const double rhs) {
return my_vector(lhs) += rhs;
}
inline my_vector operator-(const my_vector& lhs, const double rhs) {
return my_vector(lhs) -= rhs;
}
inline my_vector operator*(const my_vector& lhs, const double rhs) {
return my_vector(lhs) *= rhs;
}
inline my_vector operator/(const my_vector& lhs, const double rhs) {
return my_vector(lhs) /= rhs;
}
inline double mean(const my_vector& obj) {
const std::size_t size = obj.size();
if (size == 0) return 0;
double t = 0;
for (auto e : obj) t += e;
return t / size;
}
inline double sd(const my_vector& obj) {
const std::size_t size = obj.size();
if (size < 2) return 0;
double m = mean(obj);
double t = 0;
for (auto e : obj) t += (e - m) * (e - m);
return std::sqrt(t / (size - 1));
}
inline double norm(const my_vector& obj) {
double t = 0;
for (auto e : obj) t += e * e;
return std::sqrt(t);
}
追記
上記のヘッダーをgccでコンパイルすると以下のエラーが発生する。
error: invalid initialization of non-const reference of type 'my_vector& {aka std::vector<double>&}'
from an rvalue of type 'my_vector {aka std::vector<double>}'
return my_vector(lhs) += rhs;
^~~~~~~~~~~~~~
note: initializing argument 1 of 'my_vector& operator+=(my_vector&, const my_vector&)'
inline my_vector& operator+=(my_vector& lhs, const my_vector& rhs) {
一時的に生成される無名のオブジェクト(rvalue)を使用して、non-const referenceを初期化することはできないという意味らしい。以下のように修正すればコンパイルエラーは発生しない。
// 変更前
inline my_vector operator+(const my_vector& lhs, const my_vector& rhs) {
return my_vector(lhs) += rhs;
}
// 変更後
inline my_vector operator+(const my_vector& lhs, const my_vector& rhs) {
my_vector t(lhs);
return t += rhs;
}
生成したオブジェクトを変数に割り当てて、lvalueにしている。