Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 以CRTP作为左值的表达式模板_C++_Templates_C++11_Crtp_Expression Templates - Fatal编程技术网

C++ 以CRTP作为左值的表达式模板

C++ 以CRTP作为左值的表达式模板,c++,templates,c++11,crtp,expression-templates,C++,Templates,C++11,Crtp,Expression Templates,我正在编写一个库,它使用CRTP的表达式模板。可以在此处找到源文件: 表达式模板基于Wikipedia关于该主题的文章中给出的示例。我在这里列出了代码,以防Wiki文章将来发生更改: #include <vector> #include <cassert> template <typename E> // A CRTP base class for Vecs with a size and indexing: class VecExpression { pu

我正在编写一个库,它使用CRTP的表达式模板。可以在此处找到源文件:

表达式模板基于Wikipedia关于该主题的文章中给出的示例。我在这里列出了代码,以防Wiki文章将来发生更改:

#include <vector>
#include <cassert>

template <typename E>
// A CRTP base class for Vecs with a size and indexing:
class VecExpression {
public:
  typedef std::vector<double>         container_type;
  typedef container_type::size_type   size_type;
  typedef container_type::value_type  value_type;
  typedef container_type::reference   reference;

  size_type  size()                  const { return static_cast<E const&>(*this).size(); }
  value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i];     }

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

// The actual Vec class:
class Vec : public VecExpression<Vec> {
  container_type _data;
public:
  reference  operator[](size_type i)       { return _data[i]; }
  value_type operator[](size_type i) const { return _data[i]; }
  size_type  size()                  const { return _data.size(); }

  Vec(size_type n) : _data(n) {} // Construct a given size:

  // Construct from any VecExpression:
  template <typename E>
  Vec(VecExpression<E> const& vec) {
    E const& v = vec;
    _data.resize(v.size());
    for (size_type i = 0; i != v.size(); ++i) {
      _data[i] = v[i];
    }
  }
};

template <typename E1, typename E2>
class VecDifference : public VecExpression<VecDifference<E1, E2> > {
  E1 const& _u;
  E2 const& _v;
public:
  typedef Vec::size_type size_type;
  typedef Vec::value_type value_type;
  VecDifference(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
    assert(u.size() == v.size());
  }
  size_type size() const { return _v.size(); }
  value_type operator[](Vec::size_type i) const { return _u[i] - _v[i]; }
};

template <typename E>
class VecScaled : public VecExpression<VecScaled<E> > {
  double _alpha; 
  E const& _v;
public:
  VecScaled(double alpha, VecExpression<E> const& v) : _alpha(alpha), _v(v) {}
  Vec::size_type size() const { return _v.size(); }
  Vec::value_type operator[](Vec::size_type i) const { return _alpha * _v[i]; }
};

// Now we can overload operators:

template <typename E1, typename E2>
VecDifference<E1,E2> const
operator-(VecExpression<E1> const& u, VecExpression<E2> const& v) {
  return VecDifference<E1,E2>(u,v);
}

template <typename E>
VecScaled<E> const
operator*(double alpha, VecExpression<E> const& v) {
  return VecScaled<E>(alpha,v);
}
因此,我将创建一个新函数Vec::head,该函数将为Vec对象的一部分返回一个表达式模板。我不知道这将如何适应我目前的框架。我特别有以下问题/意见:

  • 我已经看到了我希望在不使用CRTP的表达式模板中实现的示例。在这种情况下使用CRTP有什么好处?有什么意义吗?我是否应该抛弃它,按照我发现的其他例子去做
  • 在当前框架中,对Vec类中的_数据成员的赋值由Vec类中的复制构造函数处理。如果我想使用Vec::head返回的表达式模板,这将不起作用,因为赋值发生在保存数据的类中,而不是表达式模板
  • 我尝试在新的表达式模板中创建赋值运算符,但这对上面的代码不起作用,因为所有表达式模板成员都是常量引用,因此赋值运算符在编译时被删除。我是否可以将成员转换为值而不是引用?如果需要额外的存储,这会影响性能吗?这会起作用吗(如果我更改表达式的存储副本而不是表达式本身)
  • 总的来说,我对如何在上面的代码中添加可以用作左值的表达式模板感到困惑。如果您能提供任何相关指导,我们将不胜感激。

    请尝试以下方法:

    #include <vector>
    #include <cassert>
    
    template <typename E>
    // A CRTP base class for Vecs with a size and indexing:
    class VecExpression {
    public:
        typedef std::vector<double>         container_type;
        typedef container_type::size_type   size_type;
        typedef container_type::value_type  value_type;
        typedef container_type::reference   reference;
    
        size_type  size()                  const { return static_cast<E const&>(*this).size(); }
        value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i]; }
    
        operator E&()             { return static_cast<E&>(*this); }
        operator E const&() const { return static_cast<const E&>(*this); }
    };
    
    class VecHead;
    
    // The actual Vec class:
    class Vec : public VecExpression<Vec> {
        container_type _data;
    public:
        reference  operator[](size_type i)       { return _data[i]; }
        value_type operator[](size_type i) const { return _data[i]; }
        size_type  size()                  const { return _data.size(); }
    
        Vec(size_type n) : _data(n) {} // Construct a given size:
    
        // Construct from any VecExpression:
        template <typename E>
        Vec(VecExpression<E> const& vec) {
            E const& v = vec;
            _data.resize(v.size());
            for (size_type i = 0; i != v.size(); ++i) {
                _data[i] = v[i];
            }
        }
    
        VecHead head(size_type s);
    };
    
    class VecHead : public VecExpression< VecHead >
    {
        Vec::size_type _s;
        Vec& _e;
    public:
    
        typedef Vec::size_type size_type;
        typedef Vec::value_type value_type;
        VecHead(std::size_t s, Vec& e)
            : _s(s)
            , _e(e)
        {
            assert(_e.size() >= _s);
        }
    
        size_type size() const { return _s; }
        value_type operator[](Vec::size_type i) const { assert(i < _s);  return _e[i]; }
    
        VecHead& operator = (const VecHead& rhs)
        {
            return operator=(static_cast<const VecExpression<VecHead>&>(rhs));
        }
    
        template <typename E>
        VecHead& operator = (const VecExpression<E>& rhs)
        {
            assert(rhs.size() >= _s);
            for (size_type i = 0; i < _s && i < rhs.size(); ++i)
                _e[i] = rhs[i];
            return *this;
        }
    };
    
    VecHead Vec::head(size_type s)
    {
        VecHead aHead(s, *this);
        return aHead;
    }
    
    template <typename E1, typename E2>
    class VecDifference : public VecExpression<VecDifference<E1, E2> > {
        E1 const& _u;
        E2 const& _v;
    public:
        typedef Vec::size_type size_type;
        typedef Vec::value_type value_type;
        VecDifference(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
            assert(u.size() == v.size());
        }
        size_type size() const { return _v.size(); }
        value_type operator[](Vec::size_type i) const { return _u[i] - _v[i]; }
    };
    
    template <typename E>
    class VecScaled : public VecExpression<VecScaled<E> > {
        double _alpha;
        E const& _v;
    public:
        VecScaled(double alpha, VecExpression<E> const& v) : _alpha(alpha), _v(v) {}
        Vec::size_type size() const { return _v.size(); }
        Vec::value_type operator[](Vec::size_type i) const { return _alpha * _v[i]; }
    };
    
    // Now we can overload operators:
    
    template <typename E1, typename E2>
    VecDifference<E1, E2> const
        operator-(VecExpression<E1> const& u, VecExpression<E2> const& v) {
            return VecDifference<E1, E2>(u, v);
    }
    
    template <typename E>
    VecScaled<E> const
        operator*(double alpha, VecExpression<E> const& v) {
            return VecScaled<E>(alpha, v);
    }
    
    int main()
    {
        Vec myvector(10);
        Vec another_vector(5);
        for (int i = 0; i < 5; ++i)
            another_vector[i] = i;
    
        myvector.head(5) = another_vector; // Assign first 5 elements on myvector
        assert(myvector.head(5).size() == 5);
        for (int i = 0; i < 10; ++i)
        {
            assert(myvector[i] == (i < 5 ? static_cast<double>(i) : 0.));
        }
    
        //! Added test due to comment vec1.head(2) = vec2.head(2) doesn't work.
        Vec vec1(10), vec2(10);
        for (int i = 0; i < 10; ++i)
            vec2[i] = 2 * (vec1[i] = i);
    
        vec1.head(2) = vec2.head(2);
        for (int i = 0; i < 10; ++i)
        {
            if (i < 2)
            {
                assert(vec1[i] == vec2[i]);
            }
            else
            {
                assert(vec1[i] != vec2[i]);
            }
        }
    
        return 0;
    }
    
    #包括
    #包括
    模板
    //用于具有大小和索引的VEC的CRTP基类:
    类向量表达式{
    公众:
    typedef std::向量容器_类型;
    类型定义容器类型::大小类型大小类型;
    类型定义容器类型::值类型值类型;
    类型定义容器类型::引用;
    size_type size()const{return static_cast(*this).size();}
    value_type运算符[](size_type i)const{return static_cast(*this)[i];}
    运算符E&({返回静态_cast(*this);}
    运算符E const&()const{return static_cast(*this);}
    };
    班组长;
    //实际的Vec类别:
    类Vec:公共向量表达式{
    容器类型数据;
    公众:
    引用运算符[](size_type i){return_data[i];}
    value_type运算符[](size_type i)const{return_data[i];}
    size_type size()常量{return_data.size();}
    Vec(大小\类型n):\数据(n){}//构造给定大小:
    //从任何向量表达式构造:
    模板
    向量(向量表达式常量和向量){
    E常数&v=vec;
    _data.resize(v.size());
    对于(大小类型i=0;i!=v.size();++i){
    _数据[i]=v[i];
    }
    }
    车头(s型尺寸);
    };
    类VecHead:公共VecExpression
    {
    Vec::大小\u类型\u s;
    Vec&U e;
    公众:
    typedef-Vec::size\u-type size\u-type;
    类型定义向量::值类型值类型;
    VecHead(标准:尺寸、Vec&e)
    :(s)
    ,_e(e)
    {
    断言(\u e.size()>=\u s);
    }
    size_type size()常量{return_s;}
    value_type运算符[](Vec::size_type i)const{assert(i<_s);返回_e[i];}
    向量头和运算符=(常量向量头和rhs)
    {
    返回运算符=(静态_转换(rhs));
    }
    模板
    向量头和运算符=(常量向量表达式和rhs)
    {
    断言(rhs.size()>=\u s);
    对于(大小类型i=0;i<\u s&&i
    谢谢!这在大多数情况下都能很好地工作,但如果我想执行类似于
    vec1.head(2)=vec2.head(2)
    的操作,则编译失败,出现
    错误:非静态引用成员'Vec&VecHead::_e',无法使用默认赋值运算符
    。很抱歉,我没有在标题中明确说明这个用例。嗯,我只是尝试了这个
    #include <vector>
    #include <cassert>
    
    template <typename E>
    // A CRTP base class for Vecs with a size and indexing:
    class VecExpression {
    public:
        typedef std::vector<double>         container_type;
        typedef container_type::size_type   size_type;
        typedef container_type::value_type  value_type;
        typedef container_type::reference   reference;
    
        size_type  size()                  const { return static_cast<E const&>(*this).size(); }
        value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i]; }
    
        operator E&()             { return static_cast<E&>(*this); }
        operator E const&() const { return static_cast<const E&>(*this); }
    };
    
    class VecHead;
    
    // The actual Vec class:
    class Vec : public VecExpression<Vec> {
        container_type _data;
    public:
        reference  operator[](size_type i)       { return _data[i]; }
        value_type operator[](size_type i) const { return _data[i]; }
        size_type  size()                  const { return _data.size(); }
    
        Vec(size_type n) : _data(n) {} // Construct a given size:
    
        // Construct from any VecExpression:
        template <typename E>
        Vec(VecExpression<E> const& vec) {
            E const& v = vec;
            _data.resize(v.size());
            for (size_type i = 0; i != v.size(); ++i) {
                _data[i] = v[i];
            }
        }
    
        VecHead head(size_type s);
    };
    
    class VecHead : public VecExpression< VecHead >
    {
        Vec::size_type _s;
        Vec& _e;
    public:
    
        typedef Vec::size_type size_type;
        typedef Vec::value_type value_type;
        VecHead(std::size_t s, Vec& e)
            : _s(s)
            , _e(e)
        {
            assert(_e.size() >= _s);
        }
    
        size_type size() const { return _s; }
        value_type operator[](Vec::size_type i) const { assert(i < _s);  return _e[i]; }
    
        VecHead& operator = (const VecHead& rhs)
        {
            return operator=(static_cast<const VecExpression<VecHead>&>(rhs));
        }
    
        template <typename E>
        VecHead& operator = (const VecExpression<E>& rhs)
        {
            assert(rhs.size() >= _s);
            for (size_type i = 0; i < _s && i < rhs.size(); ++i)
                _e[i] = rhs[i];
            return *this;
        }
    };
    
    VecHead Vec::head(size_type s)
    {
        VecHead aHead(s, *this);
        return aHead;
    }
    
    template <typename E1, typename E2>
    class VecDifference : public VecExpression<VecDifference<E1, E2> > {
        E1 const& _u;
        E2 const& _v;
    public:
        typedef Vec::size_type size_type;
        typedef Vec::value_type value_type;
        VecDifference(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
            assert(u.size() == v.size());
        }
        size_type size() const { return _v.size(); }
        value_type operator[](Vec::size_type i) const { return _u[i] - _v[i]; }
    };
    
    template <typename E>
    class VecScaled : public VecExpression<VecScaled<E> > {
        double _alpha;
        E const& _v;
    public:
        VecScaled(double alpha, VecExpression<E> const& v) : _alpha(alpha), _v(v) {}
        Vec::size_type size() const { return _v.size(); }
        Vec::value_type operator[](Vec::size_type i) const { return _alpha * _v[i]; }
    };
    
    // Now we can overload operators:
    
    template <typename E1, typename E2>
    VecDifference<E1, E2> const
        operator-(VecExpression<E1> const& u, VecExpression<E2> const& v) {
            return VecDifference<E1, E2>(u, v);
    }
    
    template <typename E>
    VecScaled<E> const
        operator*(double alpha, VecExpression<E> const& v) {
            return VecScaled<E>(alpha, v);
    }
    
    int main()
    {
        Vec myvector(10);
        Vec another_vector(5);
        for (int i = 0; i < 5; ++i)
            another_vector[i] = i;
    
        myvector.head(5) = another_vector; // Assign first 5 elements on myvector
        assert(myvector.head(5).size() == 5);
        for (int i = 0; i < 10; ++i)
        {
            assert(myvector[i] == (i < 5 ? static_cast<double>(i) : 0.));
        }
    
        //! Added test due to comment vec1.head(2) = vec2.head(2) doesn't work.
        Vec vec1(10), vec2(10);
        for (int i = 0; i < 10; ++i)
            vec2[i] = 2 * (vec1[i] = i);
    
        vec1.head(2) = vec2.head(2);
        for (int i = 0; i < 10; ++i)
        {
            if (i < 2)
            {
                assert(vec1[i] == vec2[i]);
            }
            else
            {
                assert(vec1[i] != vec2[i]);
            }
        }
    
        return 0;
    }