C++ 如何使用表达式模板来实现数学向量类的标量乘法 请考虑下面的(部分)数学向量类的实现(基本上是你可以在其中找到的代码): 名称空间数学 { 模板 类向量_表达式 { 公众: std::size\u t size()常量{ 返回静态_cast(*this).size(); } 双运算符[](大小i)常量 { 如果(i>=size()) 抛出标准::长度_错误(“”); 返回静态_cast(*this)[i]; } 运算符E&({返回静态_cast(*this);} 运算符E const&()const{return static_cast(*this);} };//类向量_表达式 模板 类向量和 :公共向量_表达式 { 公众: 向量和(向量表达式常数和e1,向量表达式常数和e2) :m_e1(e1),m_e2(e2) { 如果(e1.size()!=e2.size()) 抛出std::逻辑_错误(“”); } std::size\u t size()常量{ 返回m_e1.size();/==m_e2.size() } 双运算符[](标准::大小i)常量{ 返回m_e1[i]+m_e2[i]; } 私人: E1施工与维护E1; E2 const&m_E2; };//类向量_和 模板 向量和运算符+(向量表达式常量和e1,向量表达式常量和e2){ 返回{e1,e2}; } 模板 类向量 :公共向量_表达式 { 公众: 向量(标准::大小\u t d) :m_数据(d) { } 向量(std::初始值设定项\列表初始值) :m_数据(初始) { } 模板 向量(向量表达式常量和表达式) :m_数据(expression.size()) { 对于(std::size_t i=0;i

C++ 如何使用表达式模板来实现数学向量类的标量乘法 请考虑下面的(部分)数学向量类的实现(基本上是你可以在其中找到的代码): 名称空间数学 { 模板 类向量_表达式 { 公众: std::size\u t size()常量{ 返回静态_cast(*this).size(); } 双运算符[](大小i)常量 { 如果(i>=size()) 抛出标准::长度_错误(“”); 返回静态_cast(*this)[i]; } 运算符E&({返回静态_cast(*this);} 运算符E const&()const{return static_cast(*this);} };//类向量_表达式 模板 类向量和 :公共向量_表达式 { 公众: 向量和(向量表达式常数和e1,向量表达式常数和e2) :m_e1(e1),m_e2(e2) { 如果(e1.size()!=e2.size()) 抛出std::逻辑_错误(“”); } std::size\u t size()常量{ 返回m_e1.size();/==m_e2.size() } 双运算符[](标准::大小i)常量{ 返回m_e1[i]+m_e2[i]; } 私人: E1施工与维护E1; E2 const&m_E2; };//类向量_和 模板 向量和运算符+(向量表达式常量和e1,向量表达式常量和e2){ 返回{e1,e2}; } 模板 类向量 :公共向量_表达式 { 公众: 向量(标准::大小\u t d) :m_数据(d) { } 向量(std::初始值设定项\列表初始值) :m_数据(初始) { } 模板 向量(向量表达式常量和表达式) :m_数据(expression.size()) { 对于(std::size_t i=0;i,c++,templates,c++11,c++14,C++,Templates,C++11,C++14,我应该如何扩展此实现以允许以下操作: 向量x={…}; 自动y=4711*x;//或y=x*4711 自动z=1+x;//或者x+1,应该产生z[i]=x[i]+1 我想我需要像这样的东西 namespace math { template<class E, typename T> class vector_product : public vector_expression<vector_product<E, T>>

我应该如何扩展此实现以允许以下操作:

向量x={…}; 自动y=4711*x;//或y=x*4711 自动z=1+x;//或者x+1,应该产生z[i]=x[i]+1 我想我需要像这样的东西

namespace math
{
    template<class E, typename T>
    class vector_product
        : public vector_expression<vector_product<E, T>>
    {
    public:
        vector_product(vector_expression<E> const& e, T const& t)
            : m_e(e), m_t(t)
        { }

        std::size_t size() const {
            return m_e.size();
        }

        double operator[](std::size_t i) const {
            return m_e[i] * m_t;
        }

    private:
        E const& m_e;
        T const& m_t;
    }; // class vector_product

    template<class E, typename T>
    vector_product<E, T> operator*(vector_expression<E> const& e, T const& t) {
        return { e, t };
    }
    template<class E, typename T>
    vector_product<E, T> operator*(T const& t, vector_expression<E> const& e) {
        return e * t;
    }   
} // namespace math
名称空间数学
{
模板
类向量乘积
:公共向量_表达式
{
公众:
向量积(向量表达式常数&e,T常数&T)
:m_e(e),m_t(t)
{ }
std::size\u t size()常量{
返回m_e.size();
}
双运算符[](标准::大小i)常量{
返回m_e[i]*m_t;
}
私人:
施工与维护工程;
施工与维护;
};//类向量_积
模板
向量乘积运算符*(向量表达式常数&e,T常数&T){
返回{e,t};
}
模板
向量乘积运算符*(T常数&T,向量表达式常数&e){
返回e*t;
}   
}//名称空间数学

但我不知道这是否是一个好方法。那么,我该怎么做呢?我应该添加任何复制或移动构造函数/赋值运算符吗?我想不会,因为隐式变量应该做得很好,因为
vector
的唯一成员变量是STL类型。

我只想扩展
vector\u sum
,允许
E2
,如果是,则优雅地处理它。这将涉及在构造函数中获取
E1常量&
E2常量&
的参数,可能不会产生大小差异(因为标量没有大小),并重写
操作符[]
以不进行索引。对于最后一部分,类似于:

    double operator[](std::size_t i) const {
        return m_e1[i] + get(m_e2, i);
    }

private:
    template <class E>
    double get(E const& rhs, std::size_t i) const {
        return rhs[i];
    }

    double get(double scalar, std::size_t ) const {
        return scalar;
    }
这让你可以写:

math::vector<int> x = {1, 2, 3, 4};
math::vector<int> y = {2, 3, 4, 5};    
auto sum = 3 + x + 1;
向量x={1,2,3,4}; 向量y={2,3,4,5}; 自动求和=3+x+1;


保留对const的引用可能不是正确的做法-如果您这样做了
a+b+c
,您将最终保留对临时
a+b
的引用。您可能只想保留对实际
向量的引用,并保留所有中间对象的副本



要支持
向量积
,您可能希望
向量和
真正成为
向量二进制
,然后
向量积
应该是
向量二进制
。这样,就不会有所有的重复。

E=double
专门化
模板类向量表达式

添加最小/最大大小的概念(因为双精度是0到无限维),并且可能
是标量(可能不需要,除非转换为标量?)

杀死向量求和并拿走它的玩具。生成对元素进行元素操作的
binop\u向量

friend binop\u向量
运算符+(向量_表达式常量和l.R常量和R){
返回{l,r};
}
友元binop_向量
运算符+(双常量和l.向量表达式常量和r){
返回{l,r};
}
对于
*
ElemMult
向量表达式
类似。binop使用元素操作来实现
[]

更改断言以确保最小/最大大小重叠。在
binop\u向量中报告交点

vector_表达式
重载的最小值为0 max-1(size_t),并始终返回其值。如果需要多个标量类型,请编写
标量表达式
并从中继承
向量表达式
(等)


以上内容没有经过测试,只是在我坐在车库里的时候写在电话上。

受亚克和巴里的启发,我终于得出以下结论:

namespace math
{
    template<class E>
    class expression
    {
    public:
        auto size() const {
            return static_cast<E const&>(*this).size();
        }

        auto operator[](std::size_t i) const
        {
            if (i >= size())
                throw std::length_error("");
            return static_cast<E const&>(*this)[i];
        }

        operator E&() { return static_cast<E&>(*this); }
        operator E const&() const { return static_cast<E const&>(*this); }
    }; // class expression

    template<typename T, class Allocator = std::allocator<T>>
    class vector
        : public expression<vector<T>>
    {
    private:
        using data_type = std::vector<T, Allocator>;
        data_type m_data;

    public:
        using value_type = T;
        using allocator_type = Allocator;
        using size_type = typename data_type::size_type;
        using difference_type = typename data_type::difference_type;
        using reference = typename data_type::reference;
        using const_reference = typename data_type::const_reference;
        using pointer = typename data_type::pointer ;
        using const_pointer = typename data_type::const_pointer;

        vector(size_type d)
            : m_data(d)
        { }
        vector(std::initializer_list<value_type> init)
            : m_data(init)
        { }
        template<class E>
        vector(expression<E> const& expression)
            : m_data(expression.size())
        {
            for (size_type i = 0; i < expression.size(); ++i)
                m_data[i] = expression[i];
        }

        size_type size() const {
            return m_data.size();
        }

        value_type  operator[](size_type i) const { return m_data[i]; }
        value_type& operator[](size_type i)       { return m_data[i]; };
    }; // class vector

    namespace detail
    {
        template<typename T>
        class scalar
            : public expression<scalar<T>>
        {
        public:
            using value_type = T;
            using allocator_type = std::allocator<void>;
            using size_type = typename std::allocator<T>::size_type;
            using difference_type = typename std::allocator<T>::difference_type;
            using reference = typename std::allocator<T>::reference;
            using const_reference = typename std::allocator<T>::const_reference;
            using pointer = typename std::allocator<T>::pointer;
            using const_pointer = typename std::allocator<T>::const_pointer;

            scalar(value_type value)
                : m_value(value)
            { }

            size_type size() const {
                return 0;
            }

            operator value_type&() { return static_cast<value_type&>(*this); }
            operator value_type const&() const { return static_cast<value_type const&>(*this); }

            value_type  operator[](size_type i) const { return m_value; }
            value_type& operator[](size_type i) { return m_value; }

        private:
            value_type m_value;
        }; // class scalar

        template<class>
        struct is_scalar : std::false_type { };

        template<class T>
        struct is_scalar<scalar<T>> : std::true_type { };
    } // namespace detail

    template<class E1, class E2, class BinaryOperation>
    class vector_binary_operation
        : public expression<vector_binary_operation<E1, E2, BinaryOperation>>
    {
    public:
        using value_type = decltype(BinaryOperation()(typename E1::value_type(), typename E2::value_type()));
        using allocator_type = std::conditional_t<
            detail::is_scalar<E1>::value,
            typename E2::allocator_type::template rebind<value_type>::other,
            typename E1::allocator_type::template rebind<value_type>::other>;

    private:
        using vector_type = vector<value_type, allocator_type>;

    public:
        using size_type = typename vector_type::size_type;
        using difference_type = typename vector_type::difference_type;
        using reference = typename vector_type::reference;
        using const_reference = typename vector_type::const_reference;
        using pointer = typename vector_type::pointer;
        using const_pointer = typename vector_type::const_pointer;

        vector_binary_operation(expression<E1> const& e1, expression<E2> const& e2, BinaryOperation op)
            : m_e1(e1), m_e2(e2),
              m_op(op)
        {
            if (e1.size() > 0 && e2.size() > 0 && !(e1.size() == e2.size()))
                throw std::logic_error("");
        }

        size_type size() const {
            return m_e1.size(); // == m_e2.size()
        }

        value_type operator[](size_type i) const {
            return m_op(m_e1[i], m_e2[i]);
        }

    private:
        E1 m_e1;
        E2 m_e2;
        //E1 const& m_e1;
        //E2 const& m_e2;
        BinaryOperation m_op;
    }; // class vector_binary_operation

    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::plus<>>
    operator+(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::plus<>() };
    }
    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::minus<>>
    operator-(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::minus<>() };
    }
    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::multiplies<>>
    operator*(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::multiplies<>() };
    }
    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::divides<>>
    operator/(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::divides<>() };
    }

    template<class E, typename T>
    vector_binary_operation<E, detail::scalar<T>, std::divides<>>
    operator/(expression<E> const& expr, T val) {
        return{ expr, detail::scalar<T>(val), std::divides<>() };
    }
    template<class E, typename T>
    vector_binary_operation<E, detail::scalar<T>, std::multiplies<>>
    operator*(T val, expression<E> const& expr) {
        return{ expr, detail::scalar<T>(val), std::multiplies<>() };
    }
    template<class E, typename T>
    vector_binary_operation<E, detail::scalar<T>, std::multiplies<>>
    operator*(expression<E> const& expr, T val) {
        return{ expr, detail::scalar<T>(val), std::multiplies<>() };
    }
} // namespace math
名称空间数学
{
模板
类表达式
template <typename E1>
vector_sum<E1, double> operator+(vector_expression<E1> const& e1, double d) {
        return {e1, d};
}

template <typename E1>
vector_sum<E1, double> operator+(double d, vector_expression<E1> const& e1) {
        return {e1, d};
}
math::vector<int> x = {1, 2, 3, 4};
math::vector<int> y = {2, 3, 4, 5};    
auto sum = 3 + x + 1;
friend binop_vector<vector_expression,R,ElemAdd>
operator+( vector_expression const& l. R const& r ){
  return {l,r};
}
friend binop_vector<vector_expression<double>,vector_expression,ElemAdd>
operator+( double const& l. vector_expression const const& r ){
  return {l,r};
}
namespace math
{
    template<class E>
    class expression
    {
    public:
        auto size() const {
            return static_cast<E const&>(*this).size();
        }

        auto operator[](std::size_t i) const
        {
            if (i >= size())
                throw std::length_error("");
            return static_cast<E const&>(*this)[i];
        }

        operator E&() { return static_cast<E&>(*this); }
        operator E const&() const { return static_cast<E const&>(*this); }
    }; // class expression

    template<typename T, class Allocator = std::allocator<T>>
    class vector
        : public expression<vector<T>>
    {
    private:
        using data_type = std::vector<T, Allocator>;
        data_type m_data;

    public:
        using value_type = T;
        using allocator_type = Allocator;
        using size_type = typename data_type::size_type;
        using difference_type = typename data_type::difference_type;
        using reference = typename data_type::reference;
        using const_reference = typename data_type::const_reference;
        using pointer = typename data_type::pointer ;
        using const_pointer = typename data_type::const_pointer;

        vector(size_type d)
            : m_data(d)
        { }
        vector(std::initializer_list<value_type> init)
            : m_data(init)
        { }
        template<class E>
        vector(expression<E> const& expression)
            : m_data(expression.size())
        {
            for (size_type i = 0; i < expression.size(); ++i)
                m_data[i] = expression[i];
        }

        size_type size() const {
            return m_data.size();
        }

        value_type  operator[](size_type i) const { return m_data[i]; }
        value_type& operator[](size_type i)       { return m_data[i]; };
    }; // class vector

    namespace detail
    {
        template<typename T>
        class scalar
            : public expression<scalar<T>>
        {
        public:
            using value_type = T;
            using allocator_type = std::allocator<void>;
            using size_type = typename std::allocator<T>::size_type;
            using difference_type = typename std::allocator<T>::difference_type;
            using reference = typename std::allocator<T>::reference;
            using const_reference = typename std::allocator<T>::const_reference;
            using pointer = typename std::allocator<T>::pointer;
            using const_pointer = typename std::allocator<T>::const_pointer;

            scalar(value_type value)
                : m_value(value)
            { }

            size_type size() const {
                return 0;
            }

            operator value_type&() { return static_cast<value_type&>(*this); }
            operator value_type const&() const { return static_cast<value_type const&>(*this); }

            value_type  operator[](size_type i) const { return m_value; }
            value_type& operator[](size_type i) { return m_value; }

        private:
            value_type m_value;
        }; // class scalar

        template<class>
        struct is_scalar : std::false_type { };

        template<class T>
        struct is_scalar<scalar<T>> : std::true_type { };
    } // namespace detail

    template<class E1, class E2, class BinaryOperation>
    class vector_binary_operation
        : public expression<vector_binary_operation<E1, E2, BinaryOperation>>
    {
    public:
        using value_type = decltype(BinaryOperation()(typename E1::value_type(), typename E2::value_type()));
        using allocator_type = std::conditional_t<
            detail::is_scalar<E1>::value,
            typename E2::allocator_type::template rebind<value_type>::other,
            typename E1::allocator_type::template rebind<value_type>::other>;

    private:
        using vector_type = vector<value_type, allocator_type>;

    public:
        using size_type = typename vector_type::size_type;
        using difference_type = typename vector_type::difference_type;
        using reference = typename vector_type::reference;
        using const_reference = typename vector_type::const_reference;
        using pointer = typename vector_type::pointer;
        using const_pointer = typename vector_type::const_pointer;

        vector_binary_operation(expression<E1> const& e1, expression<E2> const& e2, BinaryOperation op)
            : m_e1(e1), m_e2(e2),
              m_op(op)
        {
            if (e1.size() > 0 && e2.size() > 0 && !(e1.size() == e2.size()))
                throw std::logic_error("");
        }

        size_type size() const {
            return m_e1.size(); // == m_e2.size()
        }

        value_type operator[](size_type i) const {
            return m_op(m_e1[i], m_e2[i]);
        }

    private:
        E1 m_e1;
        E2 m_e2;
        //E1 const& m_e1;
        //E2 const& m_e2;
        BinaryOperation m_op;
    }; // class vector_binary_operation

    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::plus<>>
    operator+(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::plus<>() };
    }
    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::minus<>>
    operator-(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::minus<>() };
    }
    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::multiplies<>>
    operator*(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::multiplies<>() };
    }
    template<class E1, class E2>
    vector_binary_operation<E1, E2, std::divides<>>
    operator/(expression<E1> const& e1, expression<E2> const& e2) {
        return{ e1, e2, std::divides<>() };
    }

    template<class E, typename T>
    vector_binary_operation<E, detail::scalar<T>, std::divides<>>
    operator/(expression<E> const& expr, T val) {
        return{ expr, detail::scalar<T>(val), std::divides<>() };
    }
    template<class E, typename T>
    vector_binary_operation<E, detail::scalar<T>, std::multiplies<>>
    operator*(T val, expression<E> const& expr) {
        return{ expr, detail::scalar<T>(val), std::multiplies<>() };
    }
    template<class E, typename T>
    vector_binary_operation<E, detail::scalar<T>, std::multiplies<>>
    operator*(expression<E> const& expr, T val) {
        return{ expr, detail::scalar<T>(val), std::multiplies<>() };
    }
} // namespace math