Meugiwara
Meugiwara

Reputation: 749

Is there a C++ template way to loop on different enums?

In this topic I would like to know if a C++ way is possible to loop on different given enums ? The following source code is my proposition but doesn't compile.

enum class Fruit : int
{
    UNKNOWN = 0,
    APPLE   = 1
};
 
enum class Vegetable : int
{
    UNKNOWN = 0,
    CARROT  = 1
};
 
static const std::map<std::string, Fruit> FRUITS_MAP
{
    {"unknown", Fruit::UNKNOWN},
    {"apple",   Fruit::APPLE}
};
 
static const std::map<std::string, Vegetable> VEGETABLES_MAP
{
    {"unknown", Vegetable::UNKNOWN},
    {"carrot",  Vegetable::CARROT}
};

template<typename T>
T myFunction(const std::string &iName)
{
    T result{T(0)};
    if (std::is_same<T, Fruit>::value)
    {
        const auto &found = FRUITS_MAP.find(iName);
        if (FRUITS_MAP.end() != found)
        {
            result = found->second;
        }
    }
    else if (std::is_same<T, Vegetable>::value)
    {
        const auto &found = VEGETABLES_MAP.find(iName);
        if (VEGETABLES_MAP.end() != found)
        {
            result = found->second;
        }
    }
    return result;
}

I can't write methods with only changing return type because I get error: ambiguating

Upvotes: 0

Views: 120

Answers (1)

Klaus
Klaus

Reputation: 25623

You can fix your code simply by adding constexpr in the lines:

if constexpr (std::is_same<T, Fruit>::value)
...
else if constexpr (std::is_same<T, Vegetable>::value)

And use it like:

std::cout << static_cast<int>(myFunction<Fruit>("apple")) << std::endl;
std::cout << static_cast<int>(myFunction<Vegetable>("carrot")) << std::endl;

If you sit on a decade outdated compiler ( why? ) you can simply use specialized templates:

template<typename T> T myFunction(const std::string &iName);

    template<>
Fruit myFunction<Fruit>(const std::string &iName)
{
    Fruit result{Fruit(0)};
    const auto &found = FRUITS_MAP.find(iName);
    if (FRUITS_MAP.end() != found)
    {
        result = found->second;
    }

    return result;
}

    template<>
Vegetable myFunction<Vegetable>(const std::string &iName)
{
    Vegetable result{Vegetable(0)};
    const auto &found = VEGETABLES_MAP.find(iName);
    if (VEGETABLES_MAP.end() != found)
    {
        result = found->second;
    }

    return result;
}

But here we can ask why we need templates as simply overloads with different names have the same effect. It depends on the real use case. If you have type lists you walk over with some MTP stuff, this may help, if it is handcrafted code which will call the given functions, the template stuff makes no sense.

Upvotes: 2

Related Questions