我试图让程序员(使用我的库)创建类型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
的几乎线性解析。我该怎么做呢?答案 0 :(得分: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;
}
请注意,由于模板参数是地址,因此不会进行实际字符串比较。你不能,例如,使用
X& vanilla = NamedX<"Vanilla">::value;
因为"Vanilla"
是没有外部联系的prvalue。所以,实际上你可以做到没有一些复杂性,而是使用标签结构: Live on Coliru
答案 1 :(得分:0)
虽然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_";
当然,缺点是你必须确保你在任何你需要的地方通过酒吧,但工作得体。 这就是我的小参数管理器库中的样子: https://raw.github.com/vuplea/arg_manager.h/master/arg_manager.h