[英]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;
}
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.