7

(regex.cpp) では、ライブラリの作成者がカスタム構造体 (magic_number) とこの構造体の検証関数を作成して、カスタム構造体をプログラム オプションに統合する方法を示しています。彼の例に従って、カスタム クラス (MyClass) の検証関数を作成しました。Compiler は、MyClass で lexical_cast を使用できないと文句を言います。次に、コードを実装std::istream& operator>>(std::istream& in, MyClass& d)して削除void validate(.., MyClass*, ..)すると、コードがコンパイルされます。operator>>私の例では が必要ないのに、なぜこの例が を必要としないのか、誰でも説明できますvalidateか?

編集:

#include <MyLib/MyClass.h>

std::istream& operator>>(std::istream& in, MyClass& obj) {
    // some code to populate obj
    return in;
}


po::variables_map parseCommandLine(int argc, char* argv[]) {

    po::options_description options("Options");
    options.add_options()
        ("help", "produce help message")
        ("obj", po::value<MyClass>(), "")
        ;
    po::variables_map vm;
    store(po::command_line_parser(argc, argv)
        .options(options).run(), vm);
    notify(vm);

    return vm;
}

int main(int argc, char* argv[]) {

    try {
        po::variables_map vm = parseCommandLine(argc, argv);

        MyClass obj = vm["my"].as<MyClass>();

        cout << obj << endl;
    } catch(std::exception& e) {
        cout << e.what() << "\n";
        return 1;
    }   
    return 0;
}
  • コードは検証なしでコンパイルされます。

また、regex.cpp に最小限の変更を加えてみました。

  1. マジックナンバーを削除
  2. 追加#include <MyLib/MyClass.h>
  3. 出現するすべての magic_number を MyClass に置き換えます。
  4. 検証のすべてのコードをコメントアウトします。
  5. これはコンパイルされません。

編集:追加validate。それらのどれもコンパイラエラーを解決しませんでした。

void validate(boost::any& v, 
              const std::vector<std::string>& values,
              std::vector<MyClass>*, int)
{
}

void validate(boost::any& v, 
              const std::vector<std::string>& values,
              MyClass*, long)
{
}

void validate(boost::any& v, 
              const std::vector<std::string>& values,
              MyClass*, int)
{      
}

編集:名前空間に関連している可能性があります。

検証関数を で囲んだ後namespace boost { namespace program_options { }}、コードは op>> をオーバーロードせずにコンパイルされました。また、validate が MyClass と同じ名前空間に配置されている場合にも機能します。誰でもこれを説明できますか?

4

1 に答える 1

6

あなたが直面している基本的な問題は、C++ が文字列を任意のユーザー オブジェクトに変換する機能を提供していないことです (つまり、コードを記述せずに)。

この問題を解決するために、program_options には 2 つの可能性があります。

  • を実装operator>>します。これは標準的な C++ の方法ですが、他の領域に影響を与える可能性があります (つまり、コマンド ライン以外で特定の方法でオブジェクトを解析したい場合があります)。内部的にboost::lexical_castは、変換を実装するために使用され、 がop>>見つからない場合はエラーがスローされます。
  • validateprogram_options に固有の関数を実装しますが、オプション管理以外には影響しません。

テンプレート メタ プログラミングを使用して、提供したかどうか、validateまたはデフォルトでlexical_cast.

validateコードを提供しなかったため、 の試みが失敗した理由はわかりません。

ただし、実際の例を次に示します。

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

namespace po = boost::program_options;

namespace lib {
   class MyClass
    {
    public:
        int a;
    };

    void validate(boost::any& v,
                  const std::vector<std::string>& values,
                  MyClass*, int)
    {
        po::validators::check_first_occurrence(v);
        const string& s = po::validators::get_single_string(values);
        v = boost::any(MyClass { boost::lexical_cast<int>(s) } );
    }
}


po::variables_map parseCommandLine(int argc, char* argv[])
{
    po::options_description options("Options");
    options.add_options()
        ("help", "produce help message")
        ("obj", po::value<lib::MyClass>(), "")
        ;
    po::variables_map vm;
    store(po::command_line_parser(argc, argv)
        .options(options).run(), vm);
    notify(vm);

    return vm;
}

int main(int argc, char* argv[])
{
    try {
        po::variables_map vm = parseCommandLine(argc, argv);
        lib::MyClass obj = vm["obj"].as<lib::MyClass>();
        cout << obj.a << endl;
    } catch(std::exception& e) {
        cout << e.what() << "\n";
        return 1;
    }
    return 0;
}
  • アップデート

名前空間では、クラスと検証の両方が同じ名前空間に属している必要があります。

于 2012-11-21T14:58:21.787 に答える