Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.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++ 如何使用相同的调用签名索引和分配张量中的元素?_C++_Arrays_Vector_Matrix_Variable Assignment - Fatal编程技术网

C++ 如何使用相同的调用签名索引和分配张量中的元素?

C++ 如何使用相同的调用签名索引和分配张量中的元素?,c++,arrays,vector,matrix,variable-assignment,C++,Arrays,Vector,Matrix,Variable Assignment,好吧,我在谷歌上搜索了太久了,我只是不知道该怎么称呼这种技术,所以我想最好还是在这里问一下。如果这有一个明显的名称和/或我忽略的解决方案,请为我指出正确的方向 对于外行来说:张量是矩阵的逻辑延伸,就像矩阵是向量的逻辑延伸一样。向量是秩-1张量(在编程术语中,是一维数字数组),矩阵是秩-2张量(二维数字数组),秩-N张量就是N-D数字数组 现在,假设我有这样的张量类: template<typename T = double> // possibly also with size pa

好吧,我在谷歌上搜索了太久了,我只是不知道该怎么称呼这种技术,所以我想最好还是在这里问一下。如果这有一个明显的名称和/或我忽略的解决方案,请为我指出正确的方向

对于外行来说:张量是矩阵的逻辑延伸,就像矩阵是向量的逻辑延伸一样。向量是秩-1张量(在编程术语中,是一维数字数组),矩阵是秩-2张量(二维数字数组),秩-N张量就是N-D数字数组

现在,假设我有这样的张量类:

template<typename T = double> // possibly also with size parameters
class Tensor
{
  private: 
    T *M;  // Tensor data (C-array)
           // alternatively, std::vector<T> *M 
           // or std::array<T> *M 
           // etc., or possibly their constant-sized versions
           // using Tensor<>'s template parameters

  public: 

    ... // insert trivial fluffy stuff here 

    // read elements
    const T & operator() (size_t a, size_t b) const {
        ... // error checks etc.
        return M[a + rows*b];
    }

    // write elements
    T & operator() (size_t a, size_t b) {
        ... // error checks etc.
        return M[a + rows*b];
    }

    ... 

};
将其扩展到任意张量秩是相当简单的。但我希望能够实现一种更高级的索引/分配元素的方法:

Tensor<> B(5,5);
Tensor<> C = B( Slice(0,4,2), 2 );  // operator() (Slice(),size_t) used to GET elements
B( Slice(0,4,2), 2 ) = C;           // and SET elements 
         // (C is another tensor of the correct dimensions)
请注意,我打算对
operator()
的未检查版本使用
operator[]
。或者,我将更多地使用
std::vector
方法,使用
.at()
方法检查
操作符[]
的版本。无论如何,这是一个设计选择,除了现在的问题

我想出了以下不完整的“解决方案”。该方法仅适用于向量/矩阵(秩-1或秩-2张量),并具有许多不良副作用:

// define a simple slice class
Slice () 
{ 
  private:
    size_t 
        start, stride, end; 

  public: 
    Slice(size_t s, size_t e) : start(s), stride(1), end(e) {}
    Slice(size_t s, size_t S, size_t e) : start(s), stride(S), end(e) {}
    ...

};

template<typename T = double>
class Tensor
{
    ... // same as before

  public:       

    // define two operators() for use with slices:     

    // version for retrieving data
    const Tensor<T> & operator() (Slice r, size_t c) const {
        // use slicing logic to construct return tensor
        ...
        return M;
    {

    // version for assigning data
    Sass operator() (Slice r, size_t c) {
        // returns Sass object, defined below
        return Sass(*this, r,c);
    }

  protected:

    class Sass 
    {
        friend class Tensor<T>;

     private:        
        Tensor<T>& M;
        const Slice &R;
        const size_t c;

      public:

        Sass(Tensor<T> &M, const Slice &R, const size_t c)
            : M(M)
            , R(R)
            , c(c)
        {}

        operator Tensor<T>() const { return M; }

        Tensor<T> & operator= (const Tensor<T> &M2) {
            // use R/c to copy contents of M2 into M using the same 
            // Slice-logic as in "Tensor<T>::operator()(...) const" above
            ...

            return M;
        }

    };  
//定义一个简单的切片类
切片()
{ 
私人:
尺寸
开始、跨步、结束;
公众:
切片(大小s,大小e):开始(s),跨步(1),结束(e){}
切片(大小s,大小s,大小e):开始(s),跨步(s),结束(e){}
...
};
模板
类张量
{
…//和以前一样
公众:
//定义两个用于切片的运算符():
//用于检索数据的版本
常量张量和运算符()(切片r,大小c)常量{
//利用切片逻辑构造返回张量
...
返回M;
{
//用于分配数据的版本
Sass运算符()(切片r,大小\u t c){
//返回下面定义的Sass对象
返回Sass(*本,r,c);
}
受保护的:
类Sass
{
友元类张量;
私人:
张量&M;
常数切片&R;
const size_t c;
公众:
Sass(张量和M、常数切片和R、常数大小c)
:M(M)
,R(R)
,c(c)
{}
运算符张量()常量{return M;}
张量和运算符=(常数张量和M2){
//使用R/c将M2的内容复制到M中
//切片逻辑如上面的“Tensor::operator()(…)const”所示
...
返回M;
}
};  
但这感觉不对

对于上面列出的每个索引/赋值方法,我必须为每个这样的操作定义一个单独的
Tensor::Sass::Sass(…)
构造函数,一个新的
Tensor::Sass::operator=(…)
,以及一个新的
Tensor::operator()(…)
需要包含与相应的
Tensor::operator()(…)
中已经存在的内容相同的内容,并且使所有内容都适合于任意秩的
Tensor
,这使得这种方法非常丑陋,过于冗长,更重要的是,完全无法管理

因此,我觉得有一种更有效的方法来解决所有这些问题


有什么建议吗?

首先,我想指出一些设计问题:

T & operator() (size_t a, size_t b) const; 
建议您不能通过此方法更改矩阵,因为它是
const
。但您正在返回对矩阵元素的非ST引用,因此实际上您可以更改它。这只会编译,因为您使用的是原始指针。我建议改为使用
std::vector
,它会为您进行内存管理,并将给您一个错误,因为vector的常量版本的
操作符[]
提供了一个常量引用

关于您的实际问题,我不确定切片构造函数的参数应该做什么,也不确定Sass对象是什么(我不是母语人士,“Sass”在字典中只给了我一个翻译,意思是“厚颜无耻”、“无礼”)。 但是,我假设您希望使用切片创建一个对象,该对象允许访问由切片参数定义的矩阵子集

我建议不要使用
operator()
来访问矩阵。使用两个索引的op()访问给定元素似乎很自然。对我来说,使用类似的运算符来获得整个矩阵似乎不那么直观

这里有一个想法:创建一个Slice类,该类包含对矩阵的引用和必要的参数,这些参数定义了矩阵的哪个部分由Slice表示。这样一来,Slice就像是它定义的矩阵子集的代理,类似于一对迭代器,它可以被看作是容器子范围的代理指向。为矩阵提供一对
slice()
方法(常量和非常量)这将返回一个Slice/ConstSlice,引用调用该方法的矩阵。这样,您甚至可以检查该方法,以查看Slice的参数对它所引用的矩阵是否有意义。如果有意义且必要,您还可以添加一个转换运算符,将一个Slice转换为它自己的矩阵


一次又一次地重载操作符()并将参数用作掩码、线性索引和其他内容比帮助imo更容易混淆。
operator()
如果它做了一些大家都期望它做的自然的事情,那么它是很流畅的。如果它在任何地方都使用,它只会混淆代码。请使用命名方法。

不是答案,只是一个注释来跟进我的评论:

Tensor<bool> T(false);
// T (whatever its rank) contains all false
auto lazy = T(Slice(0,4,2));
// if I use lazy here, it will be all false
T = true;
// now T contains all true
// if I use lazy here, it will be all true
张量T(假);
//T(无论其级别如何)包含所有false
自动延迟=T(切片(0,4,2));
//如果我在这里用lazy,那就全错了
T=真;
//
T & operator() (size_t a, size_t b) const; 
Tensor<bool> T(false);
// T (whatever its rank) contains all false
auto lazy = T(Slice(0,4,2));
// if I use lazy here, it will be all false
T = true;
// now T contains all true
// if I use lazy here, it will be all true
operator double() { 
    return M.size() == 1 ? M[0] : std::numeric_limits<double>::quiet_NaN(); 
};
double a = B(3,4);
Tensor<> a = B(Slice(1,2,3),4); 
const Tensor<T> & operator() (int numOfDimensions, ...)