2

我几乎没有 c++ 经验,但现在我需要看一些经常使用表达式模板的代码,所以我正在阅读《C++ 模板:完整指南》一书的第 18 章,并研究书中提供的示例. 如果您碰巧有这本书,示例从第 328 页开始,包含所有上下文信息。

我的代码工作正常,直到我想添加对子向量索引的支持(​​第 338 页),我无法让分配工作,g++ 给出以下错误:

error: binding ‘const value_type {aka const double}’ to reference of type ‘double&’ discards qualifiers
         return v[vi[idx]];

我不知道发生了什么,我是否分配给一个常量对象?我该如何进行这项工作?这是我的代码:

#include <iostream>
#include <vector>


template<typename T>
class ET_Scalar {
    private:
        const T& s;

    public:
        ET_Scalar(const T& v) :
            s(v) {}

        T operator[](size_t) const
        {
            return s;
        }

        size_t size() const
        {
            return 0;   // Zero means it's a scalar
        }
};


template<typename T, typename V, typename VI>
class ET_SubVec {
    private:
        const V& v;
        const VI& vi;

    public:
        ET_SubVec(const V& a, const VI& b) :
            v(a), vi(b) {}

        const T operator[] (size_t idx) const
        {
            return v[vi[idx]];
        }

        T& operator[] (size_t idx)
        {
            return v[vi[idx]];
        }

        size_t size() const
        {
            return vi.size();
        }
};


// Using std::vector as storage
template<typename T, typename Rep = std::vector<T>>
class ET_Vector {
    private:
        Rep expr_rep;

    public:
        // Create vector with initial size
        explicit ET_Vector(size_t s) :
            expr_rep(s) {}

        ET_Vector(const Rep& v) :
            expr_rep(v) {}

        ET_Vector& operator=(const ET_Vector& v)
        {
            for (size_t i = 0; i < v.size(); i++)
                expr_rep[i] = v[i];

            return *this;
        }

        template<typename T2, typename Rep2>
        ET_Vector& operator=(const ET_Vector<T2, Rep2>& v)
        {
            for (size_t i = 0; i < v.size(); i++)
                expr_rep[i] = v[i];

            return *this;
        }

        size_t size() const
        {
            return expr_rep.size();
        }

        const T operator[](size_t idx) const
        {
            return expr_rep[idx];
        }

        T& operator[](size_t idx)
        {
            return expr_rep[idx];
        }


        template<typename T2, typename Rep2>
        ET_Vector<T, ET_SubVec<T, Rep, Rep2>> operator[](const ET_Vector<T2, Rep2>& vi)
        {
            return ET_Vector<T, ET_SubVec<T, Rep, Rep2>>(ET_SubVec<T, Rep, Rep2>(expr_rep, vi.rep()));
        }


        template<typename T2, typename Rep2>
        const ET_Vector<T, ET_SubVec<T, Rep, Rep2>> operator[](const ET_Vector<T2, Rep2>& vi) const
        {
            return ET_Vector<T, ET_SubVec<T, Rep, Rep2>>(ET_SubVec<T, Rep, Rep2>(expr_rep, vi.rep()));
        }


        // Return what the vector currently represents
        const Rep& rep() const
        {
            return expr_rep;
        }

        Rep& rep()
        {
            return expr_rep;
        }
};


template<typename T>
class ET_Traits {
    public:
        typedef const T& ExprRef;
};


template<typename T>
class ET_Traits<ET_Scalar<T>> {
    public:
        typedef ET_Scalar<T> ExprRef;
};


template<typename T, typename LHS, typename RHS>
class ET_Add {
    private:
        typename ET_Traits<LHS>::ExprRef lhs;
        typename ET_Traits<RHS>::ExprRef rhs;

    public:
        ET_Add(const LHS& l, const RHS& r) :
            lhs(l), rhs(r) {}

        T operator[](size_t idx) const
        {
            return lhs[idx] + rhs[idx];
        }

        size_t size() const
        {
            return (lhs.size() != 0) ? lhs.size() : rhs.size();
        }
};


template<typename T, typename LHS, typename RHS>
class ET_Mul {
    private:
        typename ET_Traits<LHS>::ExprRef lhs;
        typename ET_Traits<RHS>::ExprRef rhs;

    public:
        ET_Mul(const LHS& l, const RHS& r) :
            lhs(l), rhs(r) {}

        T operator[](size_t idx) const
        {
            return lhs[idx] * rhs[idx];
        }

        size_t size() const
        {
            return (lhs.size() != 0) ? lhs.size() : rhs.size();
        }
};


// Vector + Vector
template<typename T, typename LHS, typename RHS>
ET_Vector<T, ET_Add<T, LHS, RHS>>
operator+(const ET_Vector<T, LHS>& a, const ET_Vector<T, RHS>& b)
{
    return ET_Vector<T, ET_Add<T, LHS, RHS>>(ET_Add<T, LHS, RHS>(a.rep(), b.rep()));
}


// Scalar + Vector
template<typename T, typename RHS>
ET_Vector<T, ET_Add<T, ET_Scalar<T>, RHS>>
operator+(const T& s, const ET_Vector<T, RHS>& b)
{
    return ET_Vector<T, ET_Add<T, ET_Scalar<T>, RHS>>(ET_Add<T, ET_Scalar<T>, RHS>(ET_Scalar<T>(s), b.rep()));
}


// Vector .* Vector
template<typename T, typename LHS, typename RHS>
ET_Vector<T, ET_Mul<T, LHS, RHS>>
operator*(const ET_Vector<T, LHS>& a, const ET_Vector<T, RHS>& b)
{
    return ET_Vector<T, ET_Mul<T, LHS, RHS>>(ET_Mul<T, LHS, RHS>(a.rep(), b.rep()));
}


//Scalar * Vector
template<typename T, typename RHS>
ET_Vector<T, ET_Mul<T, ET_Scalar<T>, RHS>>
operator*(const T& s, const ET_Vector<T, RHS>& b)
{
    return ET_Vector<T, ET_Mul<T, ET_Scalar<T>, RHS>>(ET_Mul<T, ET_Scalar<T>, RHS>(ET_Scalar<T>(s), b.rep()));
}


template<typename T>
void print_vec(const T& e)
{
    for (size_t i = 0; i < e.size(); i++) {
        std::cout << e[i] << ' ';
    }

    std::cout << '\n';

    return;
}


int main()
{
    size_t N = 16;

    ET_Vector<double> x(N);
    ET_Vector<double> y(N);
    ET_Vector<double> z(N);
    ET_Vector<int> idx(N / 2);

    // Do not use auto z = [expr] here! Otherwise the type of z will still be a
    // container, and evaluation won't happen until later. But the compiler
    // will optimize necessary information away, causing errors.
    z = (6.5 + x) + (-2.0 * (1.25 + y));

    print_vec(z);

    for (int i = 0; i < 8; i++)
        idx[i] = 2 * i;

    z[idx] = -1.0 * z[idx];

    print_vec(z);

    return 0;
}

抱歉它的长度,我未能创建一个最小(非)工作示例。

4

0 回答 0