如何将类链接到枚举?

时间:2015-08-14 14:31:07

标签: c++ templates enums

我有以下代码:

#include <string>

enum class Hobbit {
    // typedef HobbitHelper helper;
    UNKNOWN = -1, Bilbo, Frodo, Samwise
};

struct HobbitHelper {
    static Hobbit decode(std::string const& s) {
        if (s == "Bilbo") {
            return Hobbit::Bilbo;
        }
        else if (s == "Frodo") {
            return Hobbit::Frodo;
        }
        else if (s == "Samwise") {
            return Hobbit::Samwise;
        }
        else {
            return Hobbit::UNKNOWN;
        }
    }
};

enum class Wizard {
    // typedef Apprentice helper;
    UNKNOWN = -1, Gandalf, Radagast, Saruman
};

struct Apprentice { // WizardHelper :)
    static Wizard decode(std::string const& s) {
        if (s == "Gandalf") {
            return Wizard::Gandalf;
        }
        else if (s == "Radagast") {
            return Wizard::Radagast;
        }
        else if (s == "Saruman") {
            return Wizard::Saruman;
        }
        else {
            return Wizard::UNKNOWN;
        }
    }
};

template <typename T>
T
decoder(std::string s)
{
    return ??::decode(s);
    // if the typedefs were allowed, I could use T::helper::decode()
}

int main()
{
    std::string s{ "Rincewind" };

    auto h = decoder<Hobbit>(s);
    auto w = decoder<Wizard>(s);
}

如何安排在decoder中调用相应的助手类(HobbitHelper或Apprentice)?我无法在枚举中声明嵌套类型,就像它是一个类一样。我也尝试从枚举中派生助手(因为助手本身没有数据),但也不允许这样做。

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

您可以在枚举类型上将helper类型特征设为外部和模板,并为每个enum明确专门化:

template <typename T> struct type_is { using type = T; };

template <typename > struct helper;

template <> struct helper<Hobbit> : type_is<HobbitHelper> { };
template <> struct helper<Wizard> : type_is<Apprentice> { };

template <typename T>
using helper_t = typename helper<T>::type;

然后decode才能访问:

template <typename T>
T decoder(std::string s)
{
    return helper_t<T>::decode(s);
}

答案 1 :(得分:1)

我的建议是部分模板专业化,虽然@Barry的答案可能更像你正在寻找的。

+--------------------------------------+------------------------------------+-------+----------+---------+------------+-------------------------------+------------------+
| Alarm ID                             | Name                               | State | Severity | Enabled | Continuous | Alarm condition               | Time constraints |
+--------------------------------------+------------------------------------+-------+----------+---------+------------+-------------------------------+------------------+
| 50d52c2f-fdaf-4767-818d-3cfd91c1848a | simple-cpu_alarm_high-26y5dsoucoub | alarm | low      | True    | True       | cpu_util > 0.1 during 1 x 60s | None             |
+--------------------------------------+------------------------------------+-------+----------+---------+------------+-------------------------------+------------------+

答案 2 :(得分:1)

最简单的方法是使用ADL。您可以使用类型标记使编译器在适当的命名空间中查找。

考虑:

template<typename T> struct adl_tag {};
namespace MiddleEarth {
    enum class Hobbit {
        // typedef HobbitHelper helper;
        UNKNOWN = -1, Bilbo, Frodo, Samwise
    };
    Hobbit decode(std::string const& s, adl_tag<Hobbit>) {
        if (s == "Bilbo") {
            return Hobbit::Bilbo;
        }
        else if (s == "Frodo") {
            return Hobbit::Frodo;
        }
        else if (s == "Samwise") {
            return Hobbit::Samwise;
        }
        else {
            return Hobbit::UNKNOWN;
        }
    }
}
template<typename T> T decode(std::string s) {
    return decode(s, adl_tag<T>());
}

这是几乎所有C ++库所采用的解决方案 - 或多或少。基本上没有额外的努力。我甚至没有提及向导。

答案 3 :(得分:1)

除了帮助问题之外,还有比级联if更好的解决方案:

static Hobbit decode(std::string const& s) {
    static std::unordered_map<std::strinng,Hobbit> choice {
        { "Bilbo", Hobbit::Bilbo },
        { "Frodo", Hobbit::Frodo },
        { "Samwise", Hobbit::Samwise }
    };
    auto f = choice.find( s );
    return f != choice.end() ? f->second : Hobbit::UNKNOWN;
}