Home > Blockchain >  Can I use SFINAE to compare enum class Value?
Can I use SFINAE to compare enum class Value?

Time:03-24

Live On Coliru

struct Banana : public FruitBase
{
    Banana(Fruit fruit, int price, std::string name, int length):
...
};

struct Apple : public FruitBase
{
    Apple(Fruit fruit, int price, std::string name):
...
};

template<typename... Ts>
std::unique_ptr<FruitBase> makeFruits(Fruit fruit, Ts&&... params)
{
    switch(fruit)
    {
    case Fruit::APPLE:
        return std::make_unique<Apple>(Fruit::APPLE, std::forward<Ts>(params)...);    
        break;
    case Fruit::BANANA:
        return std::make_unique<Banana>(Fruit::BANANA, std::forward<Ts>(params)...);    
        break;    
    }
    return nullptr;
}

int main()
{
    auto apple_ptr = makeFruits(Fruit::APPLE, 10, "gala");
    print_fruit(apple_ptr.get());
    
    auto banana_ptr = makeFruits(Fruit::BANANA, 20, "plantains", 123);
    print_fruit(banana_ptr.get());

}
main.cpp:37:5: note: candidate: 'Apple::Apple(Fruit, int, std::string)'
   37 |     Apple(Fruit fruit, int price, std::string name):
      |     ^~~~~
main.cpp:37:5: note:   candidate expects 3 arguments, 4 provided

main.cpp:26:5: note: candidate: 'Banana::Banana(Fruit, int, std::string, int)'
   26 |     Banana(Fruit fruit, int price, std::string name, int length):
      |     ^~~~~~
main.cpp:26:5: note:   candidate expects 4 arguments, 3 provided

Question> The issue is that the compiler has problems choosing which constructor for Apple and which one for Banana. I assume I could use SFINAE(i.e. with help of std::enable_if) to help compiler deduce the correct function. However, I didn't find an example where the checking is for VALUE instead of TYPE. Can someone give me a little hint here?

CodePudding user response:

Even if not taken, all branches should be valid

If argument is passed as template parameter (so known at compile time), you might do

template<Fruit fruit, typename... Ts>
std::unique_ptr<FruitBase> makeFruits(Ts&&... params)
{
    if constexpr (fruit == Fruit::APPLE)
        return std::make_unique<Apple>(Fruit::APPLE, std::forward<Ts>(params)...);
    else if constexpr (fruit == Fruit::BANANA)
        return std::make_unique<Banana>(Fruit::BANANA, std::forward<Ts>(params)...);
    else
        return nullptr;
}

int main()
{
    auto apple_ptr = makeFruits<Fruit::APPLE>(10, "gala");
    auto banana_ptr = makeFruits<Fruit::BANANA>(20, "plantains", 123);
}

Demo

You can still add SFINAE on top of that.

  •  Tags:  
  • c
  • Related