繁体   English   中英

理解具有冲突要求的常量正确性

[英]Understanding const correctness with conflicting requirements

错误: Invalid conversion from 'char**' to 'const char**'

类似的问题似乎没有相同的情况(即同一结构上具有不同 const 要求的两个函数)。 如果确实是,请仅将其标记为重复。

ROS/C++: http : //wiki.ros.org/ROS/Tutorials

参数解析器: https : //github.com/jamolnng/argparse

我需要将argv传递给来自 ROS 的函数和来自argparse标头的函数。 前者需要一个char**后者需要一个const *char[]

代码示例(基本模式仅取自两个库的示例):

int main(int argc, char **argv){
  argparse::ArgumentParser parser("Parser");

  parser.add_argument()
        .names({"-v", "--video"})
        .description("Enable video output for this node.")
        .required(false);
  parser.enable_help();

  //Problem 1: requires argv to be "const *char[]"
  auto err = parser.parse(argc, argv); 
  if (err){ /*error handling*/}

  //Problem 2: requires argv to be non-const
  ros::init(argc, argv, "node_name");

  ...

  return 0;
}

我需要调用这两个函数,但它们都需要相同结构的不同类型。 为清楚起见,函数原型:

//Declaration 1
Result parse(int argc, const char *argv[]);

//Declaration 2
void ros::init (int & argc,
                char **argv,
                const std::string &name,
                uint32_t options = 0 
                );
  1. 有没有办法可以调用这两个函数?

  2. 为什么这甚至是一个问题? 据我了解,声明 1 中的const只是一个函数parse()不会修改argv的承诺; 为什么这需要在调用范围内将变量设为consthttps://isocpp.org/wiki/faq/const-correctness )。

编辑 - 更多信息:我凭直觉测试了一个最小的工作示例,而没有参考 ROS 或 argparsing 库。 下面是测试代码:

#include <iostream>

void f(const char **a){
  std::cout << a[1] << std::endl;
}

int main(int argc, char **argv){
  // Attempt 1
  f(argv); //Causes compilation error.

  // Attempt 2
  f(const_cast<const char**>(argv)); //No compilation error and correct functionality

  return 0;
}

我进一步检查了const_cast导致了我想要的行为(在调用f()期间保持不变,仅此而已)。 将尝试 2 调整到原始问题解决了我的问题,我将在下面添加答案。

我对这里的const_cast没问题,因为我正在提升到const而不是试图解决不应修改的数据结构。 也就是说我不喜欢const_cast并且我不明白为什么在这种情况下它似乎是必要的。 我会让这个问题保持开放,看看是否有人愿意解释这个(回答上面的问题 2),我会发布我的功能解决方案。

这是一个功能性解决方案,但我不会接受它作为答案,直到我解释为什么这样做或为什么这似乎是必要的。

我变了:

auto err = parser.parse(argc, argv);

auto err = parser.parse(argc, const_cast<const char**>(argv));

隔离测试(见编辑)表明这产生了我想要的行为,据我所知在这个特定的上下文中是安全的。 认为这是一个“好”的解决方案。 我觉得const_cast是一种主要的代码气味,但我不知道为什么在这种情况下会很糟糕。

此解决方案还需要在编译时使用链接标志 -lstdc++fs。

如果您使用的是 C++17,您也可以尝试 std::as_const() 但我目前仅限于 C++11。

首先,我会想为什么不能将非常量隐式转换为常量:例如,在决定调用哪个重载时,这将是不可靠的。 相反的隐式转换是可以的。

const_cast还用于添加常量,而不仅仅是删除它。 然后, const_cast还有助于像您的情况一样调用特定的重载。 我不认为这是一个糟糕的解决方案。

void f(char **a) {};
void f(const char *a[]) {};

int main(int argc, char **argv){
  f(argv); //calls first f
  f(const_cast<const char**>(argv)); //calls second f
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM