简体   繁体   English

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

[英]Expression Templates - C++ Templates: The Complete Guide

I'm studying c++ templates and reading <<C++ Templates: The Complete Guide>>. 我正在研究c ++模板,并阅读《 C ++模板:完整指南》。 I don't understand the flowing about expression template: 我不了解表达式模板的流程:

The code as following: 代码如下:

//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()));
}

The test code: 测试代码:

//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;
}

My questions is why A_Traits for A_Scale is by value not by reference. 我的问题是为什么A_Scale的A_Traits是按值而不是按引用。

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;
};

The reason from the book as following: 本书的原因如下:

This is necessary because of the following: In general, we can declare them to be references because most temporary nodes are bound in the top-level expression and therefore live until the end of the evaluation of that complete expression. 由于以下原因,这是必要的:通常,我们可以将它们声明为引用,因为大多数临时节点都绑定在顶级表达式中,因此一直存在,直到该完整表达式的求值结束为止。 The one exception are the A_Scalar nodes. 一个例外是A_Scalar节点。 They are bound within the operator functions and might not live until the end of the evaluation of the complete expression. 它们绑定在运算符函数中,并且可能要等到完整表达式的求值结束后才能生效。 Thus, to avoid that the members refer to scalars that don't exist anymore, for scalars the operands have to get copied "by value." 因此,为避免成员引用不再存在的标量,对于标量,必须“按值”复制操作数。

More detail please refer to the chapter 18 of C++ Templates: The Complete Guide 有关更多详细信息,请参阅C ++模板的第18章:完整指南

Consider, for example, the right hand side of 考虑一下,例如,

x = 1.2*x + x*y;

What the quote says is that this is composed of two different categories. 引用所言是,这由两个不同的类别组成。

The heavy array x and y objects are not defined within this expression, but rather before it: array xy对象不是在此表达式内定义的,而是在它之前定义的:

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

So, as you build expressions using them, you don't have to worry whether they're still alive - they were defined beforehand. 因此,当您使用它们构建表达式时,不必担心它们是否仍然有效-它们是预先定义的。 Since they're heavy, you want to capture them by reference, and, fortunately, their lifetime makes that possible. 由于它们很重,因此您希望通过引用来捕获它们,幸运的是,它们的生命周期使这成为可能。

Conversely, the lightweight A_Scale objects are generated within the expression (eg, implicitly by the 1.2 above). 相反,轻量级A_Scale对象表达式生成(例如,由上述1.2隐式生成)。 Since they're temporaries, you have to worry about their lifetime. 由于他们是临时工,因此您必须担心他们的一生。 Since they're lightweight, it's not a problem. 由于它们是轻量级的,所以这不是问题。

That's the rationale for the traits class differentiating between them: the former are by reference, and the latter are by value (they are copied). 这就是特征类在它们之间进行区分的理由:前者是通过引用,后者是通过值(它们被复制)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM