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



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

类似的问题似乎没有相同的情况(即在同一结构上具有不同常量要求的两个函数(。如果真的是,请只将其标记为副本。

罗斯/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;为什么这需要调用作用域中的变量为const(https://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是一个主要的代码气味,但我不知道为什么在这种情况下它会很糟糕。

此解决方案还需要在编译时使用链接标志-lsdc++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
}

最新更新