【问题标题】:C++ : nameable objects belonging to an instance of a class, and stored in itC++:属于类实例的可命名对象,并存储在其中
【发布时间】:2013-09-20 12:53:00
【问题描述】:

我试图让程序员(使用我的库)能够创建类型为 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&lt;std::string, decltype(Xvec.size())&gt; 的开销让我为这么简单的事情感到烦恼。

可能的(?) 解决方案:在编译时将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&lt;std::string/*a trigger*/, ??/*something linking to the switch to set on*/&gt;。这确保了argV 相对于argC 的几乎线性解析。我应该如何处理?

【问题讨论】:

  • 如果名称在编译时是固定的,您可以使用各种名称创建一个枚举,然后将实例存储在数组/向量中并将枚举转换为索引。

标签: c++ indexing command-line-arguments stdstring compile-time


【解决方案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

【讨论】:

    【解决方案2】:

    虽然 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多