【boost笔记1】转

2023-07-08 14:41:16 浏览数 (1)

今天看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;
}

0 人点赞