直到 C++11,人们可以编写以下内容:
#include <vector>
using namespace std;
int main_under_test(int argc, char* argv[]) {
return 0;
}
int main() {
vector<char*> args {"--foo", "--bar"};
return main_under_test(args.size(), args.data());
}
但是,将文字值分配给非
const
char*
不再可能了。
幸运的是,从 C++11 开始,我们保证
std::string::data()
是空终止的,因此我们可以执行以下操作:
#include <string>
#include <vector>
using namespace std;
int main_under_test(int argc, char* argv[]) {
return 0;
}
int main() {
vector<string> strArgs {"--foo", "--bar"};
vector<char*> args;
for (auto & strArg : strArgs) {
args.push_back(strArg.data());
}
return main_under_test(args.size(), args.data());
}
然而,虽然这有效,但看起来不太好。有没有更好的方法从文字初始化非
vector
const
的 char*
(或数组)?
在 C++23 中:
std::vector<std::string> strings = {"--foo", "--bar"};
auto ptrs = strings
| std::views::transform([](auto &s){return s.data();})
| std::ranges::to<std::vector>();
Libstdc++ 还没有
ranges::to
,但这适用于 libc++ 和 MSVC STL。
遗憾的是,我们无法将
&std::string::data
直接传递给 transform
,因为 data()
已超载。
假设
main_under_test
将来会取代当前的 main
函数,那么对我来说,简单地使用 shell 脚本 (linux) 或批处理文件 (windows) 似乎更合适 – 您可以在其中动态修改参数无需重新编译(!) - 现在只需将 main_under_test
函数设置为真正的 main
函数即可(所以实际上是 XY 问题…)。
如果您坚持当前的方法,那么您可以使用它们来初始化数组,而不是创建指向字符串文字的指针:
char raw[][128] = { "--foo", "--bar" };
好的,现在我们有了一个 2D 数组 - 并且它不能仅仅转换为指针数组,因此在这种情况下我们需要自己在代码中执行此操作,但只需编写一次:
int main(int argc, char* argv[])
{
char raw[][128] = { "--foo", "--bar" }; // arbitrarily modifiable...
char* args[std::size(raw) + 2] = { *argv }; // the executable name (!)
char** a = args;
for(auto& r : raw)
{
*++a = r;
}
*++a = nullptr; // argv is always null-terminated as well!
return main_under_test(std::size(args) + 1, args);
}
godbolt演示。
另一种选择是简单地抛弃 const-ness (
{ const_cast<char*>("literals") }
),但随后你依赖于 main_under_test
严格承诺不修改参数,否则会产生未定义的行为,因此这种方法不太值得推荐。