迭代一系列类型

时间:2015-08-06 19:29:29

标签: c++ polymorphism

如何在不创建每种类型的实例的情况下迭代类型列表?

在我的示例中,我有一个带有方法getByName的父类,它返回子类的实例。由于无法创建typedef数组,因此getByName方法完全被破坏。使这项工作的最佳方法是什么?

一种解决方案是创建一个name指针数组,但如果有多个变量(不仅仅是name)我想要检查它,这会变得混乱。

我基本上想要一个使用循环而不是一系列if语句的干净解决方案。

#include <string>

struct Number {
    Number(const std::string &name) :name(name) {}

    // fix me!
    static Number* getByName(const std::string &name) {
        typedef types[] = {
            One,
            Two,
            Three,
        }
        for (int i = 0; i < 3; ++i) {
            if (name == types[i]::name)
                return new types[i]();
        }
        return nullptr;
    }
    const std::string name;
};

struct One :Number {
    One() :Number(name) {}
    const static std::string name;
};

struct Two :Number {
    Two() :Number(name) {}
    const static std::string name;
};

struct Three :Number {
    Three() :Number(name) {}
    const static std::string name;
};

const std::string One::name = "one";
const std::string Two::name = "two";
const std::string Three::name = "three";

3 个答案:

答案 0 :(得分:3)

您可以按照以下方式实施工厂

template <typename T>
static std::pair<std::string, std::function<Number*()>> register_helper()
{
    return { T::name, []() { return new T{}; }};
}

static Number* getByName(const std::string &name) {
    static const std::map<std::string, std::function<Number*()>> factories = {
         register_helper<One>(),
         register_helper<Two>(),
         register_helper<Three>()
    };

    auto it = factories.find(name);
    if (it == factories.end()) {
        return nullptr;
    } else {
        return it->second();
    }
}

Live Demo

答案 1 :(得分:1)

您无法以有意义的方式直接存储类型;但是,您可以存储指向工厂函数的指针,这应该同样有用:

yourView.codedSundayButtons(firstButton: ButtonSunChore1R, secondButton: ButtonSunChore1Y)

答案 2 :(得分:0)

尝试使用比之前的音高更简单的东西,并假设getByName不会经常使用不受支持的值调用。

template <typename TYPE>
Number * factory()
{
    return new TYPE();
}

static const std::map<std::string, Number*(*)()> factories =
{
    {One::name, factory<One>},
    {Two::name, factory<Two>},
    {Three::name, factory<Three>}
};

static Number* getByName(const std::string &name) 
{
    try
    {
        return factories.at(name)();
    }
    catch (std::out_of_range &e)
    {
        // Log factory called with bad name as a hint that the programmer 
        // should check calling code.
        return nullptr;
    }
}

但是如果带有错误名称的调用是预期的用例,那么困难的方法比处理异常要便宜得多。

static Number* getByName(const std::string &name) 
{
    auto factory = factories.find(name);
    if (factory != factories.end())
    {
        return factory->second();
    }
    return nullptr;
}
相关问题