option=value
语法只需包含 argparse.hpp 就可以了。
# include < argparse/argparse.hpp >
要开始解析命令行参数,请创建一个ArgumentParser
。
argparse::ArgumentParser program ( " program_name " );
注意: ArgumentParser
有一个可选的第二个参数,它是程序版本。示例: argparse::ArgumentParser program("libfoo", "1.9.0");
注意: ArgumentParser
有可选的第三个和第四个参数来控制默认参数。示例: argparse::ArgumentParser program("libfoo", "1.9.0", default_arguments::help, false);
请参阅下面的默认参数。
要添加新参数,只需调用.add_argument(...)
。您可以提供要组合在一起的参数名称的可变列表,例如-v
和--verbose
program.add_argument( " foo " );
program.add_argument( " -v " , " --verbose " ); // parameter packing
Argparse 支持多种参数类型,包括位置参数、可选参数和复合参数。您可以在下面看到如何配置每种类型:
这是位置参数的示例:
# include < argparse/argparse.hpp >
int main ( int argc, char *argv[]) {
argparse::ArgumentParser program ( " program_name " );
program. add_argument ( " square " )
. help ( " display the square of a given integer " )
. scan < ' i ' , int >();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
return 1 ;
}
auto input = program. get < int >( " square " );
std::cout << (input * input) << std::endl;
return 0 ;
}
并运行代码:
foo@bar:/home/dev/ $ ./main 15
225
这是发生的事情:
add_argument()
方法用于指定程序愿意接受哪些命令行选项。在本例中,我将其命名为 square,以便与其功能相符。.scan
方法将用户输入转换为整数。parser.get<T>(key)
方法获取解析器为给定参数存储的值。现在,让我们看看可选参数。可选参数以-
或--
开头,例如--verbose
或-a
。可选参数可以放置在输入序列中的任何位置。
argparse::ArgumentParser program ( " test " );
program.add_argument( " --verbose " )
.help( " increase output verbosity " )
.default_value( false )
.implicit_value( true );
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
if (program[ " --verbose " ] == true ) {
std::cout << " Verbosity enabled " << std::endl;
}
foo@bar:/home/dev/ $ ./main --verbose
Verbosity enabled
这是发生的事情:
--verbose
的情况下运行程序时不会引发错误。请注意,通过使用.default_value(false)
,如果未使用可选参数,则其值将自动设置为 false。.implicit_value(true)
,用户指定此选项更多的是一个标志,而不是需要值的选项。当用户提供 --verbose 选项时,其值设置为 true。 定义标志参数时,可以使用简写flag()
它与default_value(false).implicit_value(true)
相同。
argparse::ArgumentParser program ( " test " );
program.add_argument( " --verbose " )
.help( " increase output verbosity " )
.flag();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
if (program[ " --verbose " ] == true ) {
std::cout << " Verbosity enabled " << std::endl;
}
在某些情况下,您希望将可选参数设置为必需。如上所述,可选参数以-
或--
开头。您可以将这些类型的参数设为必需,如下所示:
program.add_argument( " -o " , " --output " )
.required()
.help( " specify the output file. " );
如果用户没有为此参数提供值,则会引发异常。
或者,您可以提供一个默认值,如下所示:
program.add_argument( " -o " , " --output " )
.default_value(std::string( " - " ))
.required()
.help( " specify the output file. " );
如果您需要存在可选参数但没有好的默认值,则可以将测试和访问参数结合起来,如下所示:
if ( auto fn = program.present( " -o " )) {
do_something_with (*fn);
}
与get
类似, present
方法也接受模板参数。但parser.present<T>(key)
返回std::optional<T>
,而不是返回T
,因此当用户没有为此参数提供值时,返回值比较等于std::nullopt
。
如果您想知道用户是否为具有.default_value
的参数提供了值,请检查参数是否为.is_used()
。
program.add_argument( " --color " )
.default_value(std::string{ " orange " }) // might otherwise be type const char* leading to an error when trying program.get<std::string>
.help( " specify the cat's fur color " );
try {
program. parse_args (argc, argv); // Example: ./main --color orange
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto color = program.get<std::string>( " --color " ); // "orange"
auto explicit_color = program.is_used( " --color " ); // true, user provided orange
您可能希望允许重复可选参数并将所有值收集到一处。
program.add_argument( " --color " )
.default_value<std::vector<std::string>>({ " orange " })
.append()
.help( " specify the cat's fur color " );
try {
program. parse_args (argc, argv); // Example: ./main --color red --color green --color blue
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto colors = program.get<std::vector<std::string>>( " --color " ); // {"red", "green", "blue"}
请注意, .default_value
被赋予了一个显式模板参数来匹配您想要.get
的类型。
常见的模式是重复一个参数来指示更大的值。
int verbosity = 0 ;
program.add_argument( " -V " , " --verbose " )
.action([&]( const auto &) { ++verbosity; })
.append()
.default_value( false )
.implicit_value( true )
.nargs( 0 );
program.parse_args(argc, argv); // Example: ./main -VVVV
std::cout << " verbose level: " << verbosity << std::endl; // verbose level: 4
使用program.add_mutually_exclusive_group(required = false)
创建互斥组。 `argparse` 将确保命令行上仅存在互斥组中的参数之一:
auto &group = program.add_mutually_exclusive_group();
group.add_argument( " --first " );
group.add_argument( " --second " );
使用以下方法会产生错误:
foo@bar:/home/dev/ $ ./main --first 1 --second 2
Argument '--second VAR' not allowed with '--first VAR'
add_mutually_exclusive_group()
函数还接受一个required
参数,以指示至少需要一个互斥参数:
auto &group = program.add_mutually_exclusive_group( true );
group.add_argument( " --first " );
group.add_argument( " --second " );
使用以下方法会产生错误:
foo@bar:/home/dev/ $ ./main
One of the arguments '--first VAR' or '--second VAR' is required
可以将参数绑定到存储其值的变量,作为显式调用program.get<T>(arg_name)
或program[arg_name]
的替代方法
目前,这是针对bool
类型的变量(这也隐式调用flag()
)、 int
、 double
、 std::string
、 std::vector<std::string>
和std::vector<int>
实现的。如果未在命令行中指定参数,则默认值(如果设置)将设置到变量中。
bool flagvar = false ;
program.add_argument( " --flagvar " ).store_into(flagvar);
int intvar = 0 ;
program.add_argument( " --intvar " ).store_into(intvar);
double doublevar = 0 ;
program.add_argument( " --doublevar " ).store_into(doublevar);
std::string strvar;
program.add_argument( " --strvar " ).store_into(strvar);
std::vector<std::string> strvar_repeated;
program.add_argument( " --strvar-repeated " ).append().store_into(strvar_repeated);
std::vector<std::string> strvar_multi_valued;
program.add_argument( " --strvar-multi-valued " ).nargs( 2 ).store_into(strvar_multi_valued);
std::vector< int > intvar_repeated;
program.add_argument( " --intvar-repeated " ).append().store_into(intvar_repeated);
std::vector< int > intvar_multi_valued;
program.add_argument( " --intvar-multi-valued " ).nargs( 2 ).store_into(intvar_multi_valued);
可选参数以-
开头。 argparse
可以处理负数吗?答案是肯定的!
argparse::ArgumentParser program;
program.add_argument( " integer " )
.help( " Input number " )
.scan< ' i ' , int >();
program.add_argument( " floats " )
.help( " Vector of floats " )
.nargs( 4 )
.scan< ' g ' , float >();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
// Some code to print arguments
foo@bar:/home/dev/ $ ./main -5 -1.1 -3.1415 -3.1e2 -4.51329E3
integer : -5
floats : -1.1 -3.1415 -310 -4513.29
正如您在这里所看到的, argparse
支持负整数、负浮点数和科学记数法。
argparse::ArgumentParser program ( " main " );
program.add_argument( " square " )
.help( " display the square of a given number " )
.scan< ' i ' , int >();
program.add_argument( " --verbose " )
.default_value( false )
.implicit_value( true );
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
int input = program.get< int >( " square " );
if (program[ " --verbose " ] == true ) {
std::cout << " The square of " << input << " is " << (input * input) << std::endl;
}
else {
std::cout << (input * input) << std::endl;
}
foo@bar:/home/dev/ $ ./main 4
16
foo@bar:/home/dev/ $ ./main 4 --verbose
The square of 4 is 16
foo@bar:/home/dev/ $ ./main --verbose 4
The square of 4 is 16
std::cout << program
打印一条帮助消息,包括程序用法和有关使用ArgumentParser
注册的参数的信息。对于前面的示例,以下是默认帮助消息:
foo@bar:/home/dev/$ ./main --help
Usage: main [-h] [--verbose] square
Positional arguments:
square display the square of a given number
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--verbose
您还可以通过program.help().str()
获取字符串形式的帮助消息。
ArgumentParser::add_description
将在详细参数信息之前添加文本。 ArgumentParser::add_epilog
将在所有其他帮助输出之后添加文本。
# include < argparse/argparse.hpp >
int main ( int argc, char *argv[]) {
argparse::ArgumentParser program ( " main " );
program. add_argument ( " thing " ). help ( " Thing to use. " ). metavar ( " THING " );
program. add_argument ( " --member " ). help ( " The alias for the member to pass to. " ). metavar ( " ALIAS " );
program. add_argument ( " --verbose " ). default_value ( false ). implicit_value ( true );
program. add_description ( " Forward a thing to the next member. " );
program. add_epilog ( " Possible things include betingalw, chiz, and res. " );
program. parse_args (argc, argv);
std::cout << program << std::endl;
}
Usage: main [-h] [--member ALIAS] [--verbose] THING
Forward a thing to the next member.
Positional arguments:
THING Thing to use.
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--member ALIAS The alias for the member to pass to.
--verbose
Possible things include betingalw, chiz, and res.
ArgumentParser 对象通常将单个命令行参数与要执行的单个操作相关联。 .nargs
将不同数量的命令行参数与单个操作相关联。当使用nargs(N)
时,命令行中的 N 个参数将被收集到一个列表中。
argparse::ArgumentParser program ( " main " );
program.add_argument( " --input_files " )
.help( " The list of input files " )
.nargs( 2 );
try {
program. parse_args (argc, argv); // Example: ./main --input_files config.yml System.xml
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto files = program.get<std::vector<std::string>>( " --input_files " ); // {"config.yml", "System.xml"}
ArgumentParser.get<T>()
具有std::vector
和std::list
的专业化。因此,以下变体.get<std::list>
也将起作用。
auto files = program.get<std::list<std::string>>( " --input_files " ); // {"config.yml", "System.xml"}
使用.scan
,可以从命令行参数快速构建所需值类型的列表。这是一个例子:
argparse::ArgumentParser program ( " main " );
program.add_argument( " --query_point " )
.help( " 3D query point " )
.nargs( 3 )
.default_value(std::vector< double >{ 0.0 , 0.0 , 0.0 })
.scan< ' g ' , double >();
try {
program. parse_args (argc, argv); // Example: ./main --query_point 3.5 4.7 9.2
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto query_point = program.get<std::vector< double >>( " --query_point " ); // {3.5, 4.7, 9.2}
您还可以使用.nargs
创建可变长度的参数列表。以下是一些示例。
program.add_argument( " --input_files " )
.nargs( 1 , 3 ); // This accepts 1 to 3 arguments.
Python 中定义了一些有用的模式,例如 argparse 的“?”、“*”、“+”。
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::any); // "*" in Python. This accepts any number of arguments including 0.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::at_least_one); // "+" in Python. This accepts one or more number of arguments.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::optional); // "?" in Python. This accepts an argument optionally.
复合参数是组合并作为单个参数提供的可选参数。示例: ps -aux
argparse::ArgumentParser program ( " test " );
program.add_argument( " -a " )
.default_value( false )
.implicit_value( true );
program.add_argument( " -b " )
.default_value( false )
.implicit_value( true );
program.add_argument( " -c " )
.nargs( 2 )
.default_value(std::vector< float >{ 0 . 0f , 0 . 0f })
.scan< ' g ' , float >();
try {
program. parse_args (argc, argv); // Example: ./main -abc 1.95 2.47
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto a = program.get< bool >( " -a " ); // true
auto b = program.get< bool >( " -b " ); // true
auto c = program.get<std::vector< float >>( " -c " ); // {1.95, 2.47}
// / Some code that prints parsed arguments
foo@bar:/home/dev/ $ ./main -ac 3.14 2.718
a = true
b = false
c = {3.14, 2.718}
foo@bar:/home/dev/ $ ./main -cb
a = false
b = true
c = {0.0, 0.0}
这是发生的事情:
-a
、 -b
和-c
。-a
和-b
是切换参数。-c
需要来自命令行的 2 个浮点数。-abc
或-bac
或-cab
。这只适用于短的单字符参数名称。-a
和-b
变为 true。-c
输入。.default_value
定义的 {0.0, 0.0}对于输入,用户可以表达值的原始类型。
.scan<Shape, T>
方法尝试将传入的std::string
转换为遵循Shape
转换说明符的T
如果出现错误,则会引发std::invalid_argument
或std::range_error
异常。
program.add_argument( " -x " )
.scan< ' d ' , int >();
program.add_argument( " scale " )
.scan< ' g ' , double >();
Shape
指定输入“看起来像什么”,类型模板参数指定预定义操作的返回值。可接受的类型是浮点型(即float、double、long double)和整型(即signed char、short、int、long、long long)。
语法遵循std::from_chars
,但并不完全重复。例如,十六进制数字可以以0x
或0X
开头,并且带有前导零的数字可以作为八进制值处理。
形状 | 解释 |
---|---|
'a' 或 'A' | 十六进制浮点数 |
'e' 或 'E' | 科学计数法(浮点) |
'f' 或 'F' | 固定表示法(浮点) |
“g”或“G” | 一般形式(固定的或科学的) |
'd' | 小数 |
'我' | 基数 == 10 的std::from_chars 语法 |
'o' | 八进制(无符号) |
'你' | 十进制(无符号) |
“x”或“X” | 十六进制(无符号) |
argparse
为-h
/ --help
和-v
/ --version
提供预定义的参数和操作。默认情况下,这些操作将分别在显示帮助或版本消息后退出程序。此退出不会调用析构函数,从而跳过对所占用资源的清理。
这些默认参数可以在ArgumentParser
创建期间禁用,以便您可以按照自己的方式处理这些参数。 (请注意,选择默认参数时必须包含程序名称和版本。)
argparse::ArgumentParser program ( " test " , " 1.0 " , default_arguments::none);
program.add_argument( " -h " , " --help " )
.action([=]( const std::string& s) {
std::cout << help (). str ();
})
.default_value( false )
.help( " shows help message " )
.implicit_value( true )
.nargs( 0 );
上面的代码片段输出一条帮助消息并继续运行。它不支持--version
参数。
对于包含的参数,默认值为default_arguments::all
。 default_arguments::none
不会添加默认参数。 default_arguments::help
和default_arguments::version
将分别添加--help
和--version
。
可以使用默认参数,同时使用这些参数禁用默认退出。 ArgumentParser
的第四个参数 ( exit_on_default_arguments
) 是一个具有默认true值的 bool 标志。以下调用将保留--help
和--version
,但在使用这些参数时不会退出。
argparse::ArgumentParser program ( " test " , " 1.0 " , default_arguments::all, false )
argparse
支持在命令末尾收集“剩余”参数,例如,用于编译器:
foo@bar:/home/dev/ $ compiler file1 file2 file3
要启用此功能,只需创建一个参数并将其标记为remaining
即可。传递给 argparse 的所有剩余参数都聚集在这里。
argparse::ArgumentParser program ( " compiler " );
program.add_argument( " files " )
.remaining();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
try {
auto files = program. get <std::vector<std::string>>( " files " );
std::cout << files. size () << " files provided " << std::endl;
for ( auto & file : files)
std::cout << file << std::endl;
} catch (std::logic_error& e) {
std::cout << " No files provided " << std::endl;
}
当没有提供参数时:
foo@bar:/home/dev/ $ ./compiler
No files provided
当提供多个参数时:
foo@bar:/home/dev/ $ ./compiler foo.txt bar.txt baz.txt
3 files provided
foo.txt
bar.txt
baz.txt
收集剩余参数的过程也可以很好地处理可选参数: