式テンプレートに頭を悩ませようとしています。ウィキペディアの記事では、式テンプレートがその 2 つのオペランドへのconst 参照VecSum
を格納する例が示されています。Aは、 をラップする式テンプレートです。最初に質問をしてから、以下の例を完全に要約します。Vec
std::vector<double>
一時変数への const 参照を使用する式を再利用できますか? そうでない場合、軽量で再利用可能な式テンプレートをどのように実装しますか?
3 つVec
のa
、のb
場合、c
式a+b+c
は次のタイプです
VecSum<VecSum<Vec, Vec>, Vec>
私が正しく理解していれば、内部VecSum
は一時的で、外部VecSum
は内部への const 参照を格納しVecSum
ます。式が評価されるまで、内部VecSum
一時の有効期間が保証されると思います。正しい?これは、ダングリング参照を作成する危険なしに式を再利用できないことを意味しますか?a+b+c
auto expr = a + b + c;
Vec v1 = expr; // ok
Vec v2 = expr; // not ok!
もしそうなら、この例をどのように変更できますか?
- 式は再利用可能です
- 式はオペランドのコピーを格納しません(少なくとも必要でない状況では)。
完全なコード例
完全を期すために、その間にウィキペディアの記事が更新された場合に備えて、ここでサンプルコードを繰り返し、main
ダングリングリファレンスを作成すると思われる の例を示します。
#include <cassert>
#include <vector>
template <typename E>
class VecExpression {
public:
double operator[](size_t i) const
{
// Delegation to the actual expression type. This avoids dynamic polymorphism (a.k.a. virtual functions in C++)
return static_cast<E const&>(*this)[i];
}
size_t size() const { return static_cast<E const&>(*this).size(); }
};
class Vec : public VecExpression<Vec> {
std::vector<double> elems;
public:
double operator[](size_t i) const { return elems[i]; }
double &operator[](size_t i) { return elems[i]; }
size_t size() const { return elems.size(); }
Vec(size_t n) : elems(n) {}
// construct vector using initializer list
Vec(std::initializer_list<double> init) : elems(init) {}
// A Vec can be constructed from any VecExpression, forcing its evaluation.
template <typename E>
Vec(VecExpression<E> const& expr) : elems(expr.size()) {
for (size_t i = 0; i != expr.size(); ++i) {
elems[i] = expr[i];
}
}
};
template <typename E1, typename E2>
class VecSum : public VecExpression<VecSum<E1, E2> > {
E1 const& _u;
E2 const& _v;
public:
VecSum(E1 const& u, E2 const& v) : _u(u), _v(v) {
assert(u.size() == v.size());
}
double operator[](size_t i) const { return _u[i] + _v[i]; }
size_t size() const { return _v.size(); }
};
template <typename E1, typename E2>
VecSum<E1, E2>
operator+(VecExpression<E1> const& u, VecExpression<E2> const& v) {
return VecSum<E1, E2>(*static_cast<const E1*>(&u), *static_cast<const E2*>(&v));
}
int main() {
Vec v0 = {23.4,12.5,144.56,90.56};
Vec v1 = {67.12,34.8,90.34,89.30};
Vec v2 = {34.90,111.9,45.12,90.5};
auto expr = v0 + v1 + v2;
Vec v1 = expr; // ok
Vec v2 = expr; // not ok!
}
編集:
これがこの質問の複製である可能性があることに気付きました。ただし、両方の質問に対する答えは大きく異なり、すべて有用です。