/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby,
C#, OCaml, VB, Perl, Swift, Prolog, Javascript, Pascal, COBOL, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.
Here we introduce a varadic template function for the factory method.
It is still wrong because it requires adding constructor signatures
to make it compile.
To compile it requires uncommenting the lines 41,44,66,69 marked as BAD
*******************************************************************************/
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;
class Animal
{
public:
Animal () {}
Animal (string name):_name (name) {}
virtual ~ Animal () {}
virtual void action () = 0;
string name () { return _name; }
private:
string _name = {"anonymous"};
};
class Cat:public Animal
{
public:
//constructor with two arguments
Cat (const string & name, const string & color)
:Animal (name), _color (color) {}
//BAD dummy ctor with 3 arguments
//Cat(const std::string& name, const std::string& color, int legs) {};
//BAD dummy ctor with no arguments
//Cat() {}
void action ()
{
cout << "I am a cat, my name is " << name ()
<< " and my fur color is " << _color << endl;
}
private:
string _color = {"undefined"};
};
class Bug:public Animal
{
public:
//constructor with three arguments
Bug (const string & name, const string & color, int legs)
:Animal (name), _color (color), _legs (legs) {}
//BAD dummy ctor with 2 arguments
//Bug(const std::string& name, const std::string& color) {}
//BAD dummy ctor with no arguments
//Bug() {}
void action ()
{
cout << "I am a bug, my name is " << name ()
<< " and my skin color is " << _color
<< " and I jump on " << _legs << " legs"<<endl;
}
private:
string _color = {"undefined"};
int _legs = { 0 };
};
class UnknownFormOfLife:public Animal
{
public:
void action ()
{
cout << "I am an unknown form of life" << endl;
}
};
template<typename... Ts>
std::unique_ptr<Animal> makeAnimal(const std::string& animal_type, Ts&&... args)
{
// Main issue here:
// all constructor argumemts used here should be available for all type
// but there is no unique argument list useful for all.
// When this function is used from client code and instantiated, then
// - if 3 arguments are passed, the Cat constructor (2 args)
// will produce a compiler error
// - if 2 arguments are passed (ok with Cat), the Bug constructor
// will have an argument missing
// This is because all branches of the if..else if .. else should compile
// in all usage paths.
if (animal_type=="cat")
return std::make_unique<Cat>(std::forward<Ts>(args)...);
else if (animal_type=="bug")
return std::make_unique<Bug>(std::forward<Ts>(args)...);
else
return std::make_unique<UnknownFormOfLife>();
}
int main ()
{
vector < shared_ptr < Animal >> animals;
//when passing the below for makeAnimal, it only works for the cat branch
animals.push_back(makeAnimal("cat","Charlie","black"));
//the below will only work for the bug branch
animals.push_back(makeAnimal("bug","Tom","green",8));
//the below will only work for the alien branch
animals.push_back(makeAnimal("alien"));
for (auto a : animals)
a->action();
}