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);
}
You can still add SFINAE on top of that.