TadaoYamaokaの日記

山岡忠夫Homeで公開しているプログラムの開発ネタを中心に書いていきます。

C++の引数解析ライブラリ

Pythonではargparseという引数解析ライブラリが標準で使用できる。
バッテリー同梱なだけはある。

C++にはそのような便利なライブラリは用意されていないため、同じような引数解析を行おうとする煩雑な処理を実装する必要がある。
有名な引数解析ライブラリとしては、gflagsやboost::Program_optionsがあるが、ビルドに手間がかかったりする。
ヘッダー一つで使用できるライブラリがないか探したところ、cxxoptsがヘッダーオンリーでboost::Program_optionsライクな使い方ができて良さそうだった。

試した結果

試しに使ってみると、

  • 必須の引数が指定できない
  • 位置引数(positional arguments)のヘルプがオプションと区別できない

という点が望んでいたものとは違った。

必須の引数については、Issuesに上がっていたもののライブラリではサポートする気がないという回答だった。
自前でチェックが必要になるので、毎回同じようなチェック処理を書かないといけない。

2点目の位置引数のヘルプ表示については、以下のようにfileとoutputを位置引数にしている場合、

options.add_options()
	("file", "File name", cxxopts::value<std::string>(file))
	("output", "output file", cxxopts::value<std::string>())
	("d,debug", "Enable debugging")
	("h,help", "Print help")
	;
options.parse_positional({ "file", "output" });

ヘルプは以下のように表示される。

Usage:
  cxxopts_test [OPTION...] positional parameters

      --file arg    File name
      --output arg  output file
  -h, --help        Print help

これは、期待していた表示とは異なる。

ライブラリの修正

そこで、以上の2点を満たすように、ライブラリを修正した。
修正後、以下のように表示できるようになった。

usage:
  cxxopts_test [OPTION...] file output

positional arguments:
  file    File name
  output  output file

options:
  -h, --help   Print help

位置引数が不足している場合は、以下のように表示される。

usage:
  cxxopts_test [OPTION...] file output
Option 'file' is required but not present

使い方は、元のライブラリとほとんど変わっていない。
ヘルプ表示に多少コードが必要だが、argparseと似たような使い方ができる。

#include <iostream>
#include "cxxopts.hpp"

int main(int argc, char** argv)
{
	cxxopts::Options options("cxxopts_test");
	try {
		std::string file;

		options.add_options()
			("file", "File name", cxxopts::value<std::string>(file))
			("output", "output file", cxxopts::value<std::string>())
			("d,debug", "Enable debugging")
			("h,help", "Print help")
			;
		options.parse_positional({ "file", "output" });

		auto result = options.parse(argc, argv);

		if (result.count("help"))
		{
			std::cout << options.help({}) << std::endl;
			return 0;
		}

		std::cout << file << std::endl;
		std::string output = result["output"].as<std::string>();
		std::cout << output << std::endl;
	}
	catch (cxxopts::OptionException &e) {
		std::cout << options.usage() << std::endl;
		std::cerr << e.what() << std::endl;
	}

	return 0;
}

GitHubにフォークして修正したソースを置いたので、使いたい方はご自由にどうぞ。
cxxopts/cxxopts.hpp at master · TadaoYamaoka/cxxopts · GitHub