【问题标题】:Expression Templates - C++ Templates: The Complete Guide表达式模板 - C++ 模板:完整指南
【发布时间】:2016-09-29 17:08:54
【问题描述】:

我正在学习 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_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;
};

书中的原因如下:

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

更多详情请参考C++ Templates: The Complete Guide第18章

【问题讨论】:

  • 更多上下文会有所帮助。 A_Scalar 指的是什么?至少你可以提供你正在阅读的书的页面和修订版
  • 哦不好意思,可以参考这个链接:Google books
  • @Bobo 所有与回答问题相关的信息都应该在问题中。外部链接用于“如果您想了解更多”。请edit该问题无需外部链接即可回答,将来可能会失效。无论外部资源是否可用,此帖子和任何 SO 帖子都应保持相关性。
  • 此外,如果您的问题是独立的,您获得答案的机会就更高。当您让他们访问外部网站以了解您遇到的困难时,您会失去大多数愿意回答的人。
  • @bolov 感谢您的建议!我会再次编辑问题。

标签: c++ templates


【解决方案1】:

考虑,例如,右手边

x = 1.2*x + x*y;

引言说这是由两个不同的类别组成。

重的array xy 对象没有在这个表达式中定义,而是在它之前:

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

因此,当您使用它们构建表达式时,您不必担心它们是否仍然存在 - 它们是事先定义的。由于它们很重,您希望通过参考来捕捉它们,幸运的是,它们的生命周期使这成为可能。

相反,轻量级 A_Scale 对象在表达式生成(例如,由上面的 1.2 隐式生成)。因为他们是临时的,你必须担心他们的寿命。由于它们很轻,所以这不是问题。

这就是特征类区分它们的基本原理:前者是通过引用,而后者是通过值(它们被复制)。

【讨论】:

  • 你的回答启发了我。在opereator * 中创建了一个本地对象 A_Scale。所以应该是按价值计算的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-21
  • 2018-03-19
  • 2011-06-19
  • 1970-01-01
  • 2021-11-19
  • 2023-03-08
  • 1970-01-01
相关资源
最近更新 更多