2016-10-08 9 views
5

私はのような名前付きプログラムオプションを許可しない、boost_program_optionsの位置指定リストプログラムオプションを作りたいと思います。boost :: program_optionsの定位オプションに説明を追加するには?

私は次のコードスニペットがあります

#include <boost/program_options.hpp> 
#include <iostream> 
#include <string> 
#include <vector> 

namespace po = boost::program_options; 

int main(int argc, const char* argv[]) { 
    po::options_description desc("Allowed options"); 
    desc.add_options()("help", "produce help message") 
    ("files", po::value<std::vector<std::string>>()->required(), "list of files"); 

    po::positional_options_description pos; 
    pos.add("files", -1); 

    po::variables_map vm; 
    try { 
    po::store(po::command_line_parser(argc, argv).options(desc).positional(pos).run(), vm); 
    po::notify(vm); 
    } catch(const po::error& e) { 
    std::cerr << "Couldn't parse command line arguments properly:\n"; 
    std::cerr << e.what() << '\n' << '\n'; 
    std::cerr << desc << '\n'; 
    return 1; 
    } 

    if(vm.count("help") || !vm.count("files")) { 
    std::cout << desc << "\n"; 
    return 1; 
    } 
} 

問題は次のように私は位置引数リストとしてファイルのリストを読み込むことができるということです。

./a.out file1 file2 file3 

を残念ながら、このようなだけでなく(これは私は無効にしたい)

./a.out --files file1 file2 file3 

問題はまたyie LDS:

./a.out 
Couldn't parse command line arguments properly: 
the option '--files' is required but missing 

Allowed options: 
    --help    produce help message 
    --files arg   list of files 

だから私の希望のシナリオは、より多くの(似たOS)のようになる:私はdesc.add_option()(...)からfilesオプションを削除

./a.out 
Couldn't parse command line arguments properly: 
[FILES ...] is required but missing 

Allowed options: 
    --help    produce help message 
    --optionx    some random option used in future 
    [FILE ...]   list of files 

した後、それはので、私は、私はそこにそれを必要と考えている動作を停止します。

+0

名前付きパラメータで入力ファイルを指定する機能を削除する必要があるのはなぜですか?それは何にも有害ではありません、なぜそれを無効にするあなたの外出? –

+0

@DanMašek私はそれが両方の方法が有効な入力方法(私は特に1つしか必要ではなく、それをサポートするのに役立つ)を可能にするので、ユーザーにとってはそれほど明確ではないと信じています。 – Patryk

+0

OK。そこには、私には最も侵略的ではない解決策があります。引数のリスト全体に位置オプションを散らばらせることができますが、より多くのバリデーションを簡単に追加することで、より多くのオプションを制限することができます。 –

答えて

5

「boost :: program_optionsの位置指定オプションに説明を追加するにはどうすればよいですか?」のタイトルについては、no functionalityがライブラリに用意されています。その部分を自分で処理する必要があります。

質問の体は...可能ですが、やや丸まった形です。

ポジションオプションは、各ポジションを名前にマップし、その名前が存在する必要があります。コード(cmdline.cpp)でわかるように、unregisteredフラグは、位置的な引数には設定されません。 [1]、[2]

だから、あなたがやりたい、私たちは、次の操作を実行できます。

  • が助けに現れてから--filesオプションを非表示にします。ポジションオプションについては、適切なヘルプを表示する必要がありますが、これは前と同じです。
  • 解析されたオプションの解析と保存の間に、variables_mapに独自の検証を追加します。

    po::options_description desc_1; 
    // ... 
    po::options_description desc_2; 
    // ... 
    po::options_description desc_composite; 
    desc_composite.add(desc_1).add(desc_2); 
    

    我々はそのために私たちのfilesオプションを置くことができます。私たちはadd(...)メンバ関数を用いた複合options_descriptionを作成することができるという事実を利用するヘルプここ

    から--filesを隠す

hidden options_descriptionを作成し、解析段階でのみ使用するコンポジットを作成します。

は、明示的な--files

の防止(以下のコードを参照してください)私たちは、解析およびvariables_mapにそれらを保存する間にオプションのリストをインターセプトする必要があります。

command_line_parserrun()方法部材optionsbasic_option Sのベクトルを保持basic_parsed_optionsのインスタンスを返します。構文解析された各引数には要素があり、任意の位置オプションは0から列挙され、位置指定以外のオプションは位置-1になります。これを使用して、独自の検証を実行し、明示的(非定位置)の引数として--filesが見つかるとエラーを発生させることができます。

例ソースコード

See on Coliru

#include <boost/program_options.hpp> 
#include <iostream> 
#include <string> 
#include <vector> 

namespace po = boost::program_options; 

int main(int argc, const char* argv[]) 
{ 
    std::vector<std::string> file_names; 

    po::options_description desc("Allowed options"); 
    desc.add_options() 
     ("help", "produce help message") 
     ("test", "test option"); 

    std::string const FILES_KEY("files"); 

    // Hide the `files` options in a separate description 
    po::options_description desc_hidden("Hidden options"); 
    desc_hidden.add_options() 
     (FILES_KEY.c_str(), po::value(&file_names)->required(), "list of files"); 

    // This description is used for parsing and validation 
    po::options_description cmdline_options; 
    cmdline_options.add(desc).add(desc_hidden); 

    // And this one to display help 
    po::options_description visible_options; 
    visible_options.add(desc); 

    po::positional_options_description pos; 
    pos.add(FILES_KEY.c_str(), -1); 

    po::variables_map vm; 
    try { 
     // Only parse the options, so we can catch the explicit `--files` 
     auto parsed = po::command_line_parser(argc, argv) 
      .options(cmdline_options) 
      .positional(pos) 
      .run(); 

     // Make sure there were no non-positional `files` options 
     for (auto const& opt : parsed.options) { 
      if ((opt.position_key == -1) && (opt.string_key == FILES_KEY)) { 
       throw po::unknown_option(FILES_KEY); 
      } 
     } 

     po::store(parsed, vm); 
     po::notify(vm); 
    } catch(const po::error& e) { 
     std::cerr << "Couldn't parse command line arguments properly:\n"; 
     std::cerr << e.what() << '\n' << '\n'; 
     std::cerr << visible_options << '\n'; 
     return 1; 
    } 

    if (vm.count("help") || !vm.count("files")) { 
     std::cout << desc << "\n"; 
     return 1; 
    } 

    if (!file_names.empty()) { 
     std::cout << "Files: \n"; 
     for (auto const& file_name : file_names) { 
      std::cout << " * " << file_name << "\n"; 
     } 
    } 
} 

テスト出力

有効なオプション:

>example a b c --test d e 
Files: 
* a 
* b 
* c 
* d 
* e 

無効なオプション:

>example a b c --files d e 
Couldn't parse command line arguments properly: 
unrecognised option 'files' 


Allowed options: 
    --help     produce help message 
    --test     test option 
関連する問題