今天看boost库,发现一个很有意思的东西,
代码语言:javascript复制boost::program_options::options_description desc("Allowed Options");
desc.add_options()
("help", "Produce Help")
("compression", po::value<int>(), "Set compression Level");
这个add_options后边的参数个数是不确定的,例如你可以加多个参数,
代码语言:javascript复制desc.add_options()
("help", "Produce Help")
("command1", "command1 test")
("command2", "command2 test")
("command3", "command3 test")
("command4", "command4 test")
("command5", "command5 test")
("command6", "command6 test")
("command7", "command7 test");
刚看到的时候一下子没看懂,感觉这好像不是我所理解的C ,这种玩意能通过编译???
仔细想想,查了下boost的源代码,add_options声明如下:
代码语言:javascript复制options_description_easy_init add_options();
add_options方法返回一个options_description_easy_init对象,而options_description_easy_init定义如下:
class options_description_easy_init {
public:
options_description_easy_init(options_description* owner);
options_description_easy_init&
operator()(const char* name,
const char* description);
options_description_easy_init&
operator()(const char* name,
const value_semantic* s);
options_description_easy_init&
operator()(const char* name,
const value_semantic* s,
const char* description);
private:
options_description* owner;
};
看到没有,核心是options_description_easy_init重载了operator(), 并返回本身的引用, 这样,每次调用operator()运算符之后的返回可以继续调用operator(),通过这样的方法实现了参数可变个数。
以前自己也实现过类似的功能,通过宏来实现,远不如这种方法优雅。
第一次看到这样的用法,也许我火星了,深切感受到boost的强大之处阿。
附上例程源代码:
代码语言:javascript复制#include <boost/program_options.hpp>
namespace po = boost::program_options;
#include <iostream>
#include <iterator>
using namespace std;
int main(int argc, char* argv[]) {
try {
po::options_description desc("Allowed Options");
desc.add_options()
("help", "Produce Help")
("compression", po::value<int>(), "Set compression Level");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
if(vm.count("help")) {
cout << desc << "n";
return 1;
}
else if(vm.count("compression")) {
cout << "Compression level was set to "
<< vm["compression"].as<int>() << "==n";
}
else {
cout << "Compression level was not setn";
}
}
catch(exception& e) {
cerr << "error: " << e.what() << "n";
return 1;
}
catch(...) {
cerr << "Exception of unknown type!n";
}
return 0;
}
另附用宏实现的代码:
代码语言:javascript复制// Constants defintions for parameters
#define MAX_CMD_PARM_NUM 20
#define MAX_CMD_PARM_LEN 64
enum ArgType
{
ARG_INT = 0,
ARG_LONG,
ARG_DOUBLE,
ARG_STRING
};
struct ArgRec
{
enum ArgType argType;
void* argValue;
const char* argDefValue;
const char* argDesc;
};
// {{ Types definiton for command parser
#define CMD_MAP_BEGIN(cmdDesc, cmdLine)
ArgRec argTable[] = {
#define CMD_INT_ARG(storage, def, desc)
{ARG_INT, storage, def, desc},
#define CMD_LONG_ARG(storage, def, desc)
{ARG_LONG, storage, def, desc},
#define CMD_DOUBLE_ARG(storage, def, desc)
{ARG_DOUBLE, storage, def, desc},
#define CMD_STRING_ARG(storage, def, desc)
{ARG_STRING, storage, def, desc},
#define CMD_BOOL_ARG(storage, def, desc)
{ARG_BOOL, storage, def, desc},
#define CMD_MAP_END()
};
size_t narg = sizeof(argTable)/sizeof(struct ArgRec);
parserCmd(cmdLine, argTable, narg);
// }}
void parserCmd(const char* cmdLine, struct ArgRec* argRec, int narg)
{
char param[MAX_CMD_PARM_NUM][MAX_CMD_PARM_LEN];
int i;
int k;
int j = 0;
bool seenQuota = FALSE;
bool seenSpace = FALSE;
int len = (int)strlen(cmdLine);
const char* curValue = NULL;
int* intVal;
long* longVal;
double* dblVal;
bool* boolVal;
memset(param, 0, sizeof(param));
for (i = 0, k = 0; i < len; i ) {
if (cmdLine[i] == '"') {
if (!seenQuota) {
j ;
k = 0;
}
seenQuota = !seenQuota;
continue;
}
if (!seenQuota) {
if (cmdLine[i] == '(' ||
cmdLine[i] == ',' ||
cmdLine[i] == ' ' ||
cmdLine[i] == ')' ||
cmdLine[i] == 't' ||
cmdLine[i] == '<')
{
seenSpace = TRUE;
continue;
}
if (seenSpace) {
seenSpace = FALSE;
j ;
k = 0;
}
}
param[j][k ] = cmdLine[i];
}
for (i = 0; i < narg; i ) {
if (j >= i 1) curValue = param[i 1];
if (!curValue) {
curValue = argRec[i].argDefValue;
}
switch (argRec[i].argType) {
case ARG_INT:
intVal = (int*)argRec[i].argValue;
*(intVal) = atoi(curValue);
break;
case ARG_LONG:
longVal = (long*)argRec[i].argValue;
*(longVal) = atol(curValue);
break;
case ARG_DOUBLE:
dblVal = (double*)argRec[i].argValue;
*(dblVal) = atof(curValue);
break;
case ARG_STRING:
strcpy((char*)argRec[i].argValue, curValue);
break;
default:
printf("Error: Unkown parameter type:%dn", argRec[i].argType);
break;
}
curValue = NULL;
}
使用:
bool executeCommand(const char* command, const char* cmdLine)
{
if (strcasecmp(command, "ResPerCall") == 0) {
CMD_MAP_BEGIN("ResPerCall", cmdLine)
CMD_INT_ARG(&g_resultPerCall, "100", "Result per call")
CMD_MAP_END()
return true;
}
//...................
return false;
}