簡體   English   中英

C ++:屬於類實例的可命名對象,並存儲在其中

[英]C++ : nameable objects belonging to an instance of a class, and stored in it

我正在嘗試使程序員(使用我的庫)創建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""-recursive"作為觸發器)。 必要時,您應該可以輕松獲得開關的設置。 實現細節: ArgMan將具有std::unordered_map<std::string/*a trigger*/, ??/*something linking to the switch to set on*/> 這確保了argV相對於argC線性解析。 我應該如何處理?

您可以“濫用”非類型模板參數來獲取編譯時命名實例:

假設我們有一個數據類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;
}

請注意,由於模板參數是地址 ,因此沒有進行實際的字符串比較。 你不能,例如使用

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

因為"Vanilla"是沒有外部鏈接的prvalue。 因此,實際上,您可以在沒有某些復雜性的情況下執行操作,而是使用標簽結構: Live on Coliru

盡管Neil的解決方案滿足了我的要求,但它過於花哨,無法在我的庫中使用。 同樣,sehe的把戲當然有用,但是,如果我理解正確,但似乎與我的問題無關。 我已決定使用方法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_";

當然,不利的一面是您必須確保在需要的地方都通過了bar,但是效果不錯。 這就是我的小參數管理器庫中的樣子: https : //raw.github.com/vuplea/arg_manager.h/master/arg_manager.h

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM