boost::program_options 用于单字节变量

Jim*_*red 5 c++ boost boost-program-options

*强调文本*如何使用 Boost 程序选项从命令行接受单字节变量?

--id1=1 --id2=1结果的命令行参数为id1=49(或 '1', 0x31)和 id2=1。

#include <stdint.h>
#include <iostream>
#include <boost/program_options.hpp>

using namespace std;

int main(int argc, char** argv)
{
    (void)argc;
    (void)argv;
    namespace po = boost::program_options;

    const int myargc = 3;
    const char* myargv[] = {"foo","--id1=1","--id2=2" };

    uint8_t  id1;
    uint16_t id2; // works as expected.

    po::variables_map vm;
    po::options_description cmd_options( "Command options" );
    cmd_options.add_options()
    ( "id1", po::value<uint8_t >( &id1 )->default_value( 0 ), "A 1-byte ID" )
    ( "id2", po::value<uint16_t>( &id2 )->default_value( 0 ), "A 2-byte ID" )
    ;

    po::store( po::parse_command_line( myargc, myargv, cmd_options ), vm );
    po::notify( vm );
    // Using command line parameters of --id1=1 --id2=1,    
    // at this point, id1=49 (or '1', 0x31) and id2=1.
    cout << "BPO parsing of " << myargv[1] << " and " << myargv[2] << endl;
    cout << "id1: " <<      id1 << endl;
    cout << "id1: " << (int)id1 << endl;
    cout << "id2: " <<      id2 << endl;

    id1 = boost::lexical_cast<uint8_t>("1");
    id2 = boost::lexical_cast<int>("2");

    cout << "Using boost::lexical_cast" << endl;
    cout << "id1: " <<      id1 << endl;
    cout << "id1: " << (int)id1 << endl;
    cout << "id2: " <<      id2 << endl;

}
Run Code Online (Sandbox Code Playgroud)

输出是:

BPO parsing of --id1=1 and --id2=2
id1: 1
id1: 49
id2: 2
Using boost::lexical_cast
id1: 1
id1: 49
id2: 2
Run Code Online (Sandbox Code Playgroud)

Boost 最终调用 boost::lexical_cast("1")' ,它转换为字符而不是数值——“1”变成了 49 的“1”。

有没有办法更改 boost::program_options::add_options() 初始化以将单字节值视为整数而不是字符串/字符?如果没有,我有哪些选项可以更改解析或映射?明显(但不利)的选项是:[1] 不使用类似字符的值 [2] 手动解析(绕过 Boost)或 [3] 在 Boost 解析后执行二次转换。

Jim*_*red 3

创建一个数字字节类,其大小为字节,但像数值一样流,而不是像字符一样流。

#include <stdint.h>
#include <iostream>
#include <boost/program_options.hpp>

using namespace std;

struct NumByte
{
    uint8_t value;

    NumByte() : value() {}
    NumByte( const uint8_t &arg ) : value(arg) {}
    NumByte( const NumByte &arg ) : value(arg.value) {}

    operator uint8_t() const { return value; }

    friend istream& operator>>(istream& in, NumByte& valArg)
    {
        int i;
        in >> i;
        valArg.value = static_cast<uint8_t>(i);
        return in;
    }

    friend ostream& operator<<(ostream& out, NumByte& valArg)
    {
        out << static_cast<int>(valArg.value);
        return out;
    }
};

int main(int argc, char** argv)
{
    (void)argc;
    (void)argv;
    namespace po = boost::program_options;

    const int myargc = 3;
    const char* myargv[] = {"foo","--id1=1","--id2=2" };

    NumByte  id1;
    uint16_t id2; 

    po::variables_map vm;
    po::options_description cmd_options( "Command options" );
    cmd_options.add_options()
      ( "id1", po::value<NumByte >( &id1 )->default_value( 0 ), "A 1-byte ID" )
      ( "id2", po::value<uint16_t>( &id2 )->default_value( 0 ), "A 2-byte ID" )
      ;

    po::store( po::parse_command_line( myargc, myargv, cmd_options ), vm );
    po::notify( vm );

    assert( sizeof(NumByte)==1 ); // insure the size of a numeric byte is the size of a byte.

    cout << "BPO parsing of " << myargv[1] << " and " << myargv[2] << endl;
    cout << "id1: " <<      id1 << endl;
    cout << "id1: " << (int)id1 << endl;
    cout << "id2: " <<      id2 << endl;

    id1 = boost::lexical_cast<NumByte>("1");
    id2 = boost::lexical_cast<int>("2");

    cout << "Using boost::lexical_cast" << endl;
    cout << "id1: " <<      id1 << endl;
    cout << "id1: " << (int)id1 << endl;
    cout << "id2: " <<      id2 << endl;

}
Run Code Online (Sandbox Code Playgroud)

输出是:

BPO parsing of --id1=1 and --id2=2
id1: 1
id1: 1
id2: 2
Using boost::lexical_cast
id1: 1
id1: 1
id2: 2
Run Code Online (Sandbox Code Playgroud)