2

プログラマー (私のライブラリを使用する人) がX、クラスのインスタンス内に格納されているC(または少なくともそのインスタンスに限定されている) 型の名前付きインスタンスを作成できるようにしようとしています。これらは、私が思いついた唯一の(醜い)ソリューションです(言うまでもなく、私はC ++を手に入れています)

1)

class C
{
public:
    class XofC
    {
    public:
        XofC() = delete;
        XofC(C& mom)
        {
            mom.Xlist.emplace_front();
            ref = Xlist.front();
        }
        X& access()
        {
            return ref;
        }
    private:
        X& ref;
    };
    //etc
private:
    std::forward_list<X> Xlist;
    friend class XofC;
    //etc
}

問題:
どこにでも XofC インスタンスを渡さなければならない。

2)

class C
{
public:
    void newX(std::string);
    X& getX(std::string);
    //etc.
private:
    /*possible run-time mapping implementation
    std::vector<X> Xvec;
    std::unordered_map<std::string, decltype(Xvec.size())> NameMap;
    */
    //etc
}

問題:
これで問題は解決しますが、コンパイル時に X ( ) のすべての名前が認識std::stringされるため、実行時のようなものを使用することによるオーバーヘッドが、std::unordered_map<std::string, decltype(Xvec.size())>このような単純なことで私を悩ませます。

可能な ( ? ) 解決策: をコンパイル時にstd::string自動インデックスに置き換える ( int)。次に、次を使用できます。

class C
{
public:
    void newX(int); //int: unique index calculated at compile time from std::string
    X& getX(int); //int: unique index calculated at compile time from std::string
//etc.
private:
    std::vector<X> Xvec;
}

質問:

  1. 3)はありますか?
  2. 2)に対してコンパイル時の解決策は可能ですか?
  3. これは実際の状況です。私は最初の C++ "プロジェクト" を開始していましたが、ユーザー フレンドリーでシンプルかつ高速な引数管理ライブラリの実践とユーティリティを使用できると考えました。指定されたスイッチに基づいてArgManを解析できるクラスを作成する予定です。argVスイッチはプログラマーによってわかりやすい名前が付けられ、トリガー文字列が指定されます (たとえば、recurse"-r"という名前のスイッチは、トリガーとしてandを持つことができ"-recursive"ます)。必要に応じて、スイッチの設定を簡単に取得できる必要があります。実装ArgManの詳細: std::unordered_map<std::string/*a trigger*/, ??/*something linking to the switch to set on*/>. これにより、 に対する のほぼ線形の解析が保証argVされargCます。これにどのようにアプローチすればよいですか?
4

2 に答える 2

1

非型テンプレート引数を「悪用」して、コンパイル時の名前付きインスタンスを取得できます。

データクラスがあるとしますX:

#include <string> 

struct X
{
    int         has_some_properties;
    std::string data;
};

ここで、名前付きインスタンスのために、いくつかの名前定数を定義します。秘訣は、それらに外部リンケージを与えることです。これにより、アドレスを非型テンプレート引数として使用できます。

// define some character arrays **with external linkage**
namespace Names
{
    extern const char Vanilla[] = "Vanilla";
    extern const char Banana [] = "Banana";
    extern const char Coconut[] = "Coconut";
    extern const char Shoarma[] = "Shoarma";
}

ここで、型以外のテンプレート引数NamedXを取るラッパーを作成します。const char*ラッパーは(値) の静的インスタンスを保持します。X

// now we can "adorn" a `namedX` with the name constants (above)
template <const char* Name>
   struct NamedX
{
    static X value;
};

template <const char* Name> X NamedX<Name>::value;

これで、次のように使用できます。

int main()
{
    X& vanilla = NamedX<Names::Vanilla>::value;

    vanilla = { 42, "Woot!" };

    return vanilla.has_some_properties;
}

テンプレート引数がaddressesであるため、実際の文字列比較は行われないことに注意してください。たとえば、使用できません

    X& vanilla = NamedX<"Vanilla">::value;

"Vanilla"なぜなら、外部リンケージのないprvalue だからです。したがって、実際には、いくつかの複雑さをなくして、代わりにタグ構造体を使用することができます:

于 2013-09-20T15:30:36.100 に答える
0

ニールのソリューションは私が求めていたものを実行しましたが、私のライブラリで使用するにはギミックが多すぎました。また、セヘのトリックは確かに便利ですが、正しく理解できれば、私の質問とは関係ないようです。方法 1) を使用して目的の動作をエミュレートすることにしました。

class C
{
private:
    class X
    {
        //std::string member;
        //etc
    };
public:
    class XofC
    {
    public:
        XofC(C & _mom) : mom(_mom)
        {
            mom.Xlist.emplace_front();
            tehX = &(Xlist.front());
        }
        X & get(maybe)
        {
            if (&maybe != &mom) throw std::/*etc*/;
            return &tehX;
        }
    private:
        X * tehX;
        C & mom;
    };
private:
    //etc
    std::forward_list<X> Xlist;
    friend class XofC;
    //etc
};

使用法:

C foo;
bar = C::XofC(foo); //acts like an instance of X, but stored in C, but you have to use:
bar.get(foo)/*reference to the actual X*/.member = "_1_";

もちろん、欠点は、必要な場所にバーを渡す必要があることですが、適切に機能します。これは、私の小さな引数マネージャー ライブラリでどのように見えるかです: https://raw.github.com/vuplea/arg_manager.h/master/arg_manager.h

于 2013-09-29T13:20:08.433 に答える