Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.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++项目中使用GNU科学图书馆。对于CONVIONCE,我想在C++类中,将 GSLIVAuth**/COD>打包(添加一组特定于域的函数,简化接口)。但我对如何处理常量gsl_vector*感到困惑。让我解释一下。让我从这个极简包装开始 class Vector { gsl_vector* vector_; public: Vector(gsl_vector* vector): vector_(vector) {} double& operator()(int i) { return *gsl_vector_ptr(vector_, i); } };_C++ - Fatal编程技术网

常量和非常量指针的统一包装器 我在我的C++项目中使用GNU科学图书馆。对于CONVIONCE,我想在C++类中,将 GSLIVAuth**/COD>打包(添加一组特定于域的函数,简化接口)。但我对如何处理常量gsl_vector*感到困惑。让我解释一下。让我从这个极简包装开始 class Vector { gsl_vector* vector_; public: Vector(gsl_vector* vector): vector_(vector) {} double& operator()(int i) { return *gsl_vector_ptr(vector_, i); } };

常量和非常量指针的统一包装器 我在我的C++项目中使用GNU科学图书馆。对于CONVIONCE,我想在C++类中,将 GSLIVAuth**/COD>打包(添加一组特定于域的函数,简化接口)。但我对如何处理常量gsl_vector*感到困惑。让我解释一下。让我从这个极简包装开始 class Vector { gsl_vector* vector_; public: Vector(gsl_vector* vector): vector_(vector) {} double& operator()(int i) { return *gsl_vector_ptr(vector_, i); } };,c++,C++,进一步假设我有两个函数。一个定义如下: int f(Vector& x) { \\ do some math, e.g. x(0) = 0.0; return 0; } int gsl_f(gsl_vector* x) { Vector xx(x); return f(xx); } 另一个是必须使用GSL类型的回调函数,定义如下: int f(Vector& x) { \\ do some math, e.g. x(0) = 0.0; return 0

进一步假设我有两个函数。一个定义如下:

int f(Vector& x) {
  \\ do some math, e.g. x(0) = 0.0;
  return 0;
}
int gsl_f(gsl_vector* x) {
  Vector xx(x);
  return f(xx);
}
另一个是必须使用GSL类型的回调函数,定义如下:

int f(Vector& x) {
  \\ do some math, e.g. x(0) = 0.0;
  return 0;
}
int gsl_f(gsl_vector* x) {
  Vector xx(x);
  return f(xx);
}
这个很好用。现在,假设回调有一个常量签名:

int gsl_f(const gsl_vector* x);
然后我可以相应地重新定义我的
向量
类和我的
f
函数:

class Vector {
  const gsl_vector* vector_;
public:
  Vector(const gsl_vector* vector): vector_(vector) {}
  const double& operator()(int i) const {
    return *gsl_vector_const_ptr(vector_, i);
  }
};

int f(const Vector& x) {
  \\ do some math 
  return 0;
}
同样有效。现在,我希望我的包装器类能够适应这两种情况。例如,我希望能够做到以下几点,保护const的安全:


我可以使用一个带有两个指针的
向量
,const和non-const,并记住它是从const还是non-const成员初始化的。我的问题是,我能在没有运行时检查的情况下完成吗?毕竟,编译时所有的信息都在那里。

组合这两个类应该可以按预期工作,您尝试过吗

class Vector {
  gsl_vector* vector_;
public:
  Vector(gsl_vector* vector): vector_(vector) {}

  const double& operator()(int i) const {
    return *gsl_vector_ptr(vector_, i);
  }
  double& operator()(int i) {
    return *gsl_vector_ptr(vector_, i);
  }

  operator const_Vector()
  { 
    return const_Vector(vector_);
  }

};


class const_Vector {
  const gsl_vector* vector_;
public:
  const_Vector(const gsl_vector* vector): vector_(vector) {}

  const double& operator()(int i) const {
    return *gsl_vector_ptr(vector_, i);
  }
};
函数签名需要这样看:

int f(const_Vector& x, Vector& y) {
  \\ do some math 
  return 0;
}
这遵循类似于迭代器和常量迭代器的方案

也许你遇到了这样一种情况,这种情况是行不通的,。您应该发布此情况,我们可以尝试解决它。

建议(不太好,但应该有效):

第二种可能性:

class Vector { 
private:
  gsl_vector* vector_;

  Vector(gsl_vector* vector): vector_(vector) {}

public:
  static const Vector* Create (const gsl_vector* vector) {
     return new Vector (const_cast<Vector *> vector);
  }

  static Vector* Create (gsl_vector* vector) {
     return new Vector (vector);
  }

  const double& operator()(int i) const { 
    return *gsl_vector_ptr(vector_, i); 
  } 
  double& operator () (int i) {
    return *gsl_vector_ptr(vector_, i);
  }
}; 
类向量{
私人:
gsl_矢量*矢量;
向量(gsl_向量*向量):向量(向量){}
公众:
静态常量向量*创建(常量gsl_向量*向量){
返回新向量(const_cast Vector);
}
静态向量*创建(gsl_向量*向量){
返回新向量(Vector);
}
常量double&运算符()(int i)常量{
返回*gsl\u向量ptr(向量,i);
} 
double&运算符()(inti){
返回*gsl\u向量ptr(向量,i);
}
}; 

您还可以对数据指针使用某种类型的继承。进一步-模板可用于创建重载函数,根据输入指针类型返回一个或第二个版本

class JSONChannelFullConfigConst:
        public JSONObjectRenderer {
public:
    JSONChannelFullConfigConst(const uint8_t * channel_id,
                               const sensors_single_channel_config_t * cfg) :
                    j_channel_id(channel_id),
                    j_cfg(cfg) {

    }

private:
    const uint8_t * const j_channel_id;
    const sensors_single_channel_config_t * const j_cfg;
    void renderFields(rlf::UcOstreamBase& os) const;
    public:
    uint8_t getId() const {
        return *j_channel_id;
    }
};

class JSONChannelFullConfig:
        public JSONChannelFullConfigConst,
        public JSONObjectParser {
public:
    JSONChannelFullConfig(uint8_t * channel_id, sensors_single_channel_config_t * cfg) :
                    JSONChannelFullConfigConst(channel_id, cfg),
                    j_channel_id(channel_id),
                    j_cfg(cfg) {

    }
    void setId(uint8_t id) {
        *j_channel_id = id;
    }
private:
    uint8_t * const j_channel_id;
    sensors_single_channel_config_t * const j_cfg;

    virtual bool parseNameValuePair(const char * name, rlf::UcIstream & value);
};

不行。你需要两个构造函数,可能还有两个数据域,一个常量和一个非常量。想想看,你是对的,编辑了我的答案。。。现在向量可以转换为常量向量。也许Andrei应该考虑这个方向。这实际上是有两个独立的类(正如Fiktik前面提到的)。能够从向量中获得常数向量对f的签名没有帮助。在我的例子中,签名很重要,因为f使用了一个基于向量和常数向量的其他函数的完整系统,显然我不想通读整个代码并将常数向量更改为常数向量。这真的是唯一的办法吗@SVENTH我看到的唯一解决方案,不使用任何常量强制转换,如果您犯了编程错误,可能会引发一些其他难以发现的错误,可能是将向量转换为常量向量,而不是常量向量转换为向量,因此您可以使用这两种实现服务于所有情况。在这种情况下,不需要有两个不同向量的解。您应该考虑的唯一一件事是这些函数的调用频率。不知何故,编译器将编译转换,但不保证。如果这可能是一个问题,您应该编写一个基准来检查它。我怀疑这是不可能的,因为在标准容器中有两种不同类型的迭代器-
iterator
const\u iterator
。“const-wrapper of-object”和“const-wrapper of-const-object”之间有语义上的区别。我刚刚发现,在简化代码以制作一个清晰的示例时,我犯了一个错误。第一种情况(使用非常量包装器)不起作用。返回检查内容…更正了两个小错误,因此示例现在可以编译了。事实上,第一个示例遵循了我之前的想法,即运行时实现是可能的(但我猜您指的是vector_u2;(nullptr)、const_vector_2;(vector))。第二个示例禁用const安全机制。谢谢你的帖子,我会想得更多一些,但是运行时检查(例如,取消引用空指针时的segfault)到目前为止看起来最实用。对不起,是的,我已经编辑过了。因为所有“不安全”的东西都是私有的,所以第二个示例不会导致包装类之外的安全问题。请注意,在任何情况下都不会得到segfault,因为不能为常量对象调用运算符()的非常量重载。说到第二个示例,我仍然可以从常量gsl_向量*实例化它,然后进行修改。当然,此类错误的范围仅限于gsl_f等。但是,我也可以在gsl_f本身中重铸指针的明确性。