boost 的 program option 为处理复杂的命令行提供方便。
若用 VS2005 以上版本来编译程序,则当程序处理包含中文的命令行是将可能抛
“charactor conversion fail” 的异常。
现将测试后的经验总结如下:
先看一段代码:
#include "stdafx.h"
#include <boost/program_options/option.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/parsers.hpp>
#include <iostream>
#include <string>
namespace po = boost::program_options;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
std::locale::global(std::locale(""));
try {
string inName, outName;
float val;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "produce help message")
("if,i", po::value< string >(), "input file")
("of,o", po::value< string >(), "output file")
("float,f", po::value< float >( &val )->default_value(90), "a float number")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if ( argc<2 || vm.count("help")) {
cout << desc << "\n";
return 1;
}
if (vm.count("if")) {
inName = vm["if"].as<string>();
cout << "input file is : " << inName << endl;
}
if (vm.count("of")) {
outName = vm["of"].as<string>();
cout << "output file is : " << outName << endl;
}
DoSomething( inName, outName, val);
} catch (exception &e) {
cout << e.what() << endl;
}
}
1. std::locale::global(std::locale("")); 非常重要。它保证了使用操作系统当前的字符集转换器,这使得程序内部可以正确的在 ANSI-UTF16-UTF8之间转换。否则 C++默认的字符集是西文,处理中文必然出错。
2. 无论VC编译选项中,字符集是“ANSI编码”还是“Unicode 编码” (这导致 argv 的类型分别为 char * 或者 wchar_t *),上述 program option的代码都不需要改变,就当做它总是处理 ANSI 命令行一样。之所以有这个特点是 因为po::parse_command_line 有处理 char * 和 wchar_t* 两个版本。因此无论 argv 的类型如何,po::parse_command_line 总是能够正确处理。对于 Unicode (wchar_t *), 将自动转换为 utf-8 保存到 po::variables_map 中,而提取的时候总是用vm["if"].as<string>获得ANSI编码的字符串。
3. 事实上,将wchar_t *保存为 utf-8 是program option提供的处理Unicode的唯一途径。提取时只能用 vm["if"].as<string>, 而不能用 vm["if"].as<wstring>, 前者获得的是ANSI编码的字符串,而后者会抛异常 “boost::bad_any_cast: failed conversion using boost::any_cast”。