表达式模板 - C ++模板:完整指南

时间:2016-09-29 00:23:22

标签: c++ templates

我正在学习c ++模板并阅读<< C ++模板:完整指南>>。我不理解关于表达模板的流动:

代码如下:

//exprarray.h
#include <stddef.h>
#include <cassert>
#include "sarray.h"

template<typename T>
class A_Scale
{
public:
    A_Scale(T const& t):value(t){}
    T operator[](size_t) const
    {
        return value;
    }
    size_t size() const
    {
        return 0;
    }
private:
    T const& value;
};

template<typename T>
class A_Traits
{
public:
    typedef T const& exprRef;
};
template<typename T>
class A_Traits<A_Scale<T> >
{
public:
    typedef A_Scale<T> exprRef;
};

template<typename T,typename L1,typename R2>
class A_Add
{
private:
    typename A_Traits<L1>::exprRef op1;
    typename A_Traits<R2>::exprRef op2;
public:
    A_Add(L1 const& a,R2 const& b):op1(a),op2(b)
    {
    }
    T operator[](size_t indx) const
    {
        return op1[indx] + op2[indx];
    }
    size_t size() const
    {
        assert(op1.size()==0 || op2.size()==0 || op1.size() == op2.size());
        return op1.size() != 0 ? op1.size() : op2.size();
    }
};

template<typename T,typename L1,typename R2>
class A_Mul
{
private:
    typename A_Traits<L1>::exprRef op1;
    typename A_Traits<R2>::exprRef op2;
public:
    A_Mul(L1 const& a,R2 const& b):op1(a),op2(b)
    {
    }
    T operator[](size_t indx) const
    {
        return op1[indx] * op2[indx];
    }
    size_t size() const
    {
        assert(op1.size()==0 || op2.size()==0 || op1.size() == op2.size());
        return op1.size() != 0 ? op1.size():op2.size();
    }
};

template<typename T,typename Rep = SArray<T> >
class Array
{
public:
    explicit Array(size_t N):expr_Rep(N){}
    Array(Rep const& rep):expr_Rep(rep){}
    Array& operator=(Array<T> const& orig)
    {
        assert(size() == orig.size());
        for (size_t indx=0;indx < orig.size();indx++)
        {
            expr_Rep[indx] = orig[indx];
        }
        return *this;
    }
    template<typename T2,typename Rep2>
    Array& operator=(Array<T2,Rep2> const& orig)
    {
        assert(size() == orig.size());
        for (size_t indx=0;indx<orig.size();indx++)
        {
            expr_Rep[indx] = orig[indx];
        }
        return *this;
    }
    size_t size() const
    {
        return expr_Rep.size();
    }
    T operator[](size_t indx) const
    {
        assert(indx < size());
        return expr_Rep[indx];
    }
    T& operator[](size_t indx)
    {
        assert(indx < size());
        return expr_Rep[indx];
    }
    Rep const& rep() const
    {
        return expr_Rep;
    }
    Rep& rep()
    {
        return expr_Rep;
    }
private:
    Rep expr_Rep;
};

template<typename T,typename L1,typename R2>
Array<T,A_Add<T,L1,R2> >
operator+(Array<T,L1> const& a,Array<T,R2> const& b)
{
    return Array<T,A_Add<T,L1,R2> >(A_Add<T,L1,R2>(a.rep(),b.rep()));
}

template<typename T,typename L1,typename R2>
Array<T,A_Mul<T,L1,R2> >
operator*(Array<T,L1> const& a,Array<T,R2> const& b)
{
    return Array<T,A_Mul<T,L1,R2> >(A_Mul<T,L1,R2>(a.rep(),b.rep()));
}

template<typename T,typename R2>
Array<T,A_Mul<T,A_Scale<T>,R2> >
operator*(T const& a,Array<T,R2> const& b)
{
    return Array<T,A_Mul<T,A_Scale<T>,R2> >(A_Mul<T,A_Scale<T>,R2>(A_Scale<T>(a),b.rep()));
}

测试代码:

//test.cpp
#include "exprarray.h"
#include <iostream>
using namespace std;

template <typename T>
void print (T const& c)
{
    for (int i=0; i<8; ++i) {
        std::cout << c[i] << ' ';
    }
    std::cout << "..." << std::endl;
}

int main()
{
    Array<double> x(1000), y(1000);

    for (int i=0; i<1000; ++i) {
        x[i] = i;
        y[i] = x[i]+x[i];
    }

    std::cout << "x: ";
    print(x);

    std::cout << "y: ";
    print(y);

    x = 1.2 * x;
    std::cout << "x = 1.2 * x: ";
    print(x);

    x = 1.2*x + x*y;
    std::cout << "1.2*x + x*y: ";
    print(x);

    x = y;
    std::cout << "after x = y: ";
    print(x);

    return 0;
}

我的问题是为什么A_Traits for A_Scale是按值而非参考。

template<typename T>
class A_Traits
{
public:
    typedef T const& exprRef;
};
template<typename T>
class A_Traits<A_Scale<T> >
{
public:
    typedef A_Scale<T> exprRef;
};

本书的原因如下:

  

这是必要的,因为以下内容:通常,我们可以将它们声明为引用,因为大多数临时节点都绑定在顶级表达式中,因此一直存在直到该完整表达式的求值结束。一个例外是A_Scalar节点。它们绑定在运算符函数中,并且可能不会在完整表达式的求值结束之前存在。因此,为了避免成员引用不再存在的标量,对于标量,操作数必须按值复制。&#34;

更多细节请参阅C++ Templates: The Complete Guide

的第18章

1 个答案:

答案 0 :(得分:1)

例如,考虑

的右侧
x = 1.2*x + x*y;

引用的内容是,它由两个不同的类别组成。

繁重的array xy对象未在此表达式中定义,而是在其之前定义:

Array<double> x(1000), y(1000);

因此,当您使用它们构建表达式时,您不必担心它们是否还活着 - 它们是事先定义的。由于它们很重,你想通过引用来捕获它们,幸运的是,它们的生命使它成为可能。

相反,轻量级A_Scale对象在表达式中生成(例如,隐式地由上面的1.2生成)。由于他们是临时工,你不得不担心他们的一生。由于它们很轻巧,所以不是问题。

特征类区分它们的基本原理:前者是参考,后者是价值(它们被复制)。