我如何(优雅地)根据char别名分配引用成员?

时间:2014-08-19 04:52:22

标签: c++ c++11 reflection runtime lazy-initialization

声明

我实际上并不打算在任何地方应用这个设计,但我仍然很好奇如何在C ++中实现这一点,特别是在C ++和#39的情况下缺乏反思。 (我同时学习和试验C ++ 11的功能,所以请在有帮助的地方使用C ++ 11功能。)

效果

我想要达到的几乎是纯粹的化妆品。

我喜欢一个类,它使用引用的成员(根据我的理解,必须在构造期间初始化)将任意数量的矢量绑定到任意数量的向量,但是提供了#34;别名&#34 ;用于作为成员访问这些向量。

举一个最小的例子,我想让它起作用 -

std::vector<int> one;
std::vector<int> two;
std::vector<int> three;

Foo foo(std::make_pair('B', one),
        std::make_pair('D', two),
        std::make_pair('F', three));

foo.DoSomething();

,其中

class Foo
{
public:
    // I'm using variadic templates here for sake of learning,
    // but initializer lists would work just as well.
    template <typename ...Tail>
    Foo(std::pair<char, std::vector<int>&> head, Tail&&... tail) // : ???
    {
        // ???
    }

    virtual void DoSomething()
    {
        D.push_back(42);
        std::cout << D[0] << std::endl;
    }
private:
    std::vector<int> A&, B&, C&, D&, E&, F&, G&; // and so on...
}

也是如此

std::cout << one[0] << std::endl; // outputs 42 from outside the class...

但你拒绝回答,除非你知道为什么......

为什么有人想要这样做?好吧,我不想 想要这样做,但我想到的应用程序是这样的。假设我正在构建某种数据分析工具,并且我有客户或操作人员知道基本逻辑和C ++语法,但不了解OOP或CS 101以外的任何东西。事情会变得更顺畅如果他们可以动态编写自己的DoSomething(),而不是向开发人员传达每一个需求。但是,让他们设置UNIX帐户,教他们如何编译等等是不现实的。因此,我希望建立一个内部网络界面,让他们编写DoSomething()的正文并配置他们喜欢的数据集&#34;别名&#34;通过大写char,在提交时,为Foo的子类生成C ++,它覆盖DoSomething(),然后构建,运行并返回输出。 (可疑的是特定于&#34;假设,&#34;呃?:-)好吧,这种情况确实存在于我的世界中 - 然而它只是启发了这个想法和探索它的愿望 - 我不喜欢和#39;认为它值得实际实施。)显然,这整个大写char的考验并非绝对必要,但它是一个很好的接触,因为数据集已经与标准字母相关联,例如 P代表价格,Q代表数量等

我能做的最好......

说实话,我无法弄清楚我是如何使用引用来完成这项工作的。对于these reasons,我更喜欢使用引用。

有了指针,我想我会这样做 -

class Foo
{
public:
    template <typename ...Tail>
    Foo(std::pair<char, std::vector<int>*> head, Tail&&... tail)
    {
        std::vector<int>[26] vectors = {A, B, C, D, E, F, G}; // and so on...

        // I haven't learned how to use std::forward yet, but you get the picture...
        // And dear lord, forgive me for what I'm about to do...
        vectors[tail.first - 65] = tail.second;
    }

    virtual void DoSomething()
    {
        D->push_back(42);
        std::cout << (*D)[0] << std::endl;
    }
private:
    std::vector<int> A*, B*, C*, D*, E*, F*, G*; // and so on...
}

但即便如此也不是那么优雅。

  1. 有没有办法使用引用并实现这个目标?

  2. 有没有办法让这个更通用,例如。使用伪反射方法来避免再次列出所有大写字母?

  3. 有关替代设计的任何建议,以更优雅或更紧凑的方式保留主要目标(我所描述的化妆品别名)?

1 个答案:

答案 0 :(得分:1)

您可以使用以下内容:

class Foo
{
public:
    template <typename ...Ts>
    Foo(Ts&&... ts)  : m({std::forward<Ts>(ts)...}),
    A(m.at('A')),
    B(m.at('B'))
    // and so on...
    {
    }

    virtual void DoSomething()
    {
        A.push_back(42);
        std::cout << A[0] << std::endl;
    }
private:
    std::map<char, std::vector<int>&> m;
    std::vector<int> &A, &B; //, &C, &D, &E, &F, &G; // and so on...
};

但是这需要给出每个向量,所以

Foo(std::vector<int> (&v)[26]) : A(v[0]), B(v[1]) // and so on...
{
}

Foo(std::vector<int> &a, std::vector<int> &b /* And so on */) : A(a), B(b) // and so on...
{
}

似乎更合适。

Live example

如果拥有Foo的班级vector似乎更简单,那么你就会拥有

class Foo
{
public:
    virtual ~Foo() {}
    virtual void DoSomething() { /* Your code */ }

    std::vector<int>& getA() { return A; }
private:
    std::vector<int> A, B, C, D; // And so on 
};

并提供getter初始化内部向量。

然后

std::vector<int>& one = foo.GetA(); // or foo.A if you let the members public.