2016-09-29 3 views
-1

Я изучаю шаблоны C++ и читаю < < C++ Templates: The Complete Guide >>. Я не понимаю, протекающего о шаблоне выражения:Expression Templates - C++ Templates: Полное руководство

Этот код выглядит следующим образом:

//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 для 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. Они связаны внутри операторных функций и могут не доживать до конца оценки полного выражения. Таким образом, чтобы избежать того, что члены ссылаются на скаляры, которые больше не существуют, для скаляров операнды должны копироваться «по значению».

Более подробно, пожалуйста, обратитесь к главе 18 C++ Templates: The Complete Guide

+0

Больше контекста поможет. Что означает «A_Scalar»? По крайней мере, вы можете предоставить страницу и версию книги, которую вы читаете. –

+0

О, извините, вы можете сослаться на эту ссылку: [Google books] (https://books.google.com/books?id=yQU-NlmQb_UC&pg = PA331 и сжиженный газ = PA331 & дк = в + общем + мы + может + объявить + их + до + будет + ссылки +, потому что + самое + временные узлы + + являются + связаны + в + с + верхнего уровня + выражение + и + поэтому + live + до & source = bl & ots = EfoJ31UyEW & sig = AdpZxmEqmUfHcmJ6wrfGUp4Z7TU & hl = en & sa = X & ved = 0ahUKEwiGw67RsrPPAhUQ8GMKHVhIAegQ6AEIHDAA # v = onepage & q & f = false) – Bobo

+0

@Bobo Вся информация, относящаяся к ответе на вопрос, должна быть в вопросе. Внешние ссылки предназначены для «если вы хотите узнать больше».Пожалуйста, отредактируйте вопрос, который отвечает без внешних ссылок, которые могут стать недействительными в будущем. Эта должность и любая должность СО должны оставаться актуальными независимо от наличия внешних ресурсов. – bolov

ответ

1

Рассмотрим, например, правая сторона

x = 1.2*x + x*y; 

Что цитата говорит, что это состоит из двух различных категорий ,

The тяжелых arrayx и y объектов не определены в этом выражении, а до того, как:

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

Итак, как вы строите выражения, используя их, вы не должны беспокоиться, являются ли они все еще живы - они были определены заранее. Поскольку они тяжелые, вы хотите захватить их по ссылке, и, к счастью, их жизнь делает это возможным.

И наоборот, легкие A_Scale объекты генерируются в пределах выражение (например, неявно выше 1.2). Поскольку они временные, вы должны беспокоиться о своей жизни. Поскольку они легкие, это не проблема.

Это обоснование для класса признаков, дифференцирующегося между ними: первые по ссылке, а последние - по значению (они скопированы).

+0

Ваш ответ вдохновил меня. В 'opereator * 'создается локальный объект A_Scale. Так что это должно быть по стоимости. – Bobo