#include <iostream>
#include <stdexcept>
template<typename Base, typename Class, typename... Classes>
struct Factory
{
private:
// creator proc
template<typename T>
static constexpr typename std::enable_if<std::is_base_of<Base,T>::value,Base>::type*
create()
{
return new T();
}
// creator table
static Base* (*pfns[])();
public:
// return instance if in-range
Base* get(std::size_t i)
{
if (i > sizeof...(Classes))
throw std::out_of_range("Invalid class index");
return pfns[i]();
}
// return number of supported derivations
static constexpr std::size_t size()
{
return sizeof...(Classes)+1;
}
};
// static creator table
template<typename Base, typename Class, typename... Classes>
Base* (*Factory<Base,Class,Classes...>::pfns[])() =
{
Factory<Base, Class, Classes...>::template create<Class>,
Factory<Base, Class, Classes...>::template create<Classes>...
};
////////////////////////////////////////////////////////////////////////////////
class Base
{
public:
virtual ~Base()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class DeriveOne : public Base
{
public:
DeriveOne()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class DeriveTwo : public Base
{
public:
DeriveTwo()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class DeriveThree : public DeriveTwo
{
public:
DeriveThree()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
Factory<Base, DeriveOne, DeriveTwo, DeriveThree> f1;
for (std::size_t i=0; i<f1.size(); ++i)
{
Base *p = f1.get(i);
delete p;
}
return EXIT_SUCCESS;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8c3RkZXhjZXB0PgoKdGVtcGxhdGU8dHlwZW5hbWUgQmFzZSwgdHlwZW5hbWUgQ2xhc3MsIHR5cGVuYW1lLi4uIENsYXNzZXM+CnN0cnVjdCBGYWN0b3J5CnsKcHJpdmF0ZToKICAgIC8vIGNyZWF0b3IgcHJvYwogICAgdGVtcGxhdGU8dHlwZW5hbWUgVD4KICAgIHN0YXRpYyBjb25zdGV4cHIgdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8c3RkOjppc19iYXNlX29mPEJhc2UsVD46OnZhbHVlLEJhc2U+Ojp0eXBlKgogICAgY3JlYXRlKCkKICAgIHsKICAgICAgICByZXR1cm4gbmV3IFQoKTsKICAgIH0KCiAgICAvLyBjcmVhdG9yIHRhYmxlCiAgICBzdGF0aWMgQmFzZSogKCpwZm5zW10pKCk7CiAgICAKcHVibGljOgogICAgLy8gcmV0dXJuIGluc3RhbmNlIGlmIGluLXJhbmdlCiAgICBCYXNlKiBnZXQoc3RkOjpzaXplX3QgaSkKICAgIHsKICAgICAgICBpZiAoaSA+IHNpemVvZi4uLihDbGFzc2VzKSkKICAgICAgICAgICAgdGhyb3cgc3RkOjpvdXRfb2ZfcmFuZ2UoIkludmFsaWQgY2xhc3MgaW5kZXgiKTsKICAgICAgICByZXR1cm4gcGZuc1tpXSgpOwogICAgfQogICAgCiAgICAvLyByZXR1cm4gbnVtYmVyIG9mIHN1cHBvcnRlZCBkZXJpdmF0aW9ucwogICAgc3RhdGljIGNvbnN0ZXhwciBzdGQ6OnNpemVfdCBzaXplKCkKICAgIHsKICAgICAgICByZXR1cm4gc2l6ZW9mLi4uKENsYXNzZXMpKzE7CiAgICB9Cn07CgovLyBzdGF0aWMgY3JlYXRvciB0YWJsZQp0ZW1wbGF0ZTx0eXBlbmFtZSBCYXNlLCB0eXBlbmFtZSBDbGFzcywgdHlwZW5hbWUuLi4gQ2xhc3Nlcz4KQmFzZSogKCpGYWN0b3J5PEJhc2UsQ2xhc3MsQ2xhc3Nlcy4uLj46OnBmbnNbXSkoKSA9CnsKICAgIEZhY3Rvcnk8QmFzZSwgQ2xhc3MsIENsYXNzZXMuLi4+Ojp0ZW1wbGF0ZSBjcmVhdGU8Q2xhc3M+LAogICAgRmFjdG9yeTxCYXNlLCBDbGFzcywgQ2xhc3Nlcy4uLj46OnRlbXBsYXRlIGNyZWF0ZTxDbGFzc2VzPi4uLgp9OwovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKCmNsYXNzIEJhc2UKewpwdWJsaWM6CiAgICB2aXJ0dWFsIH5CYXNlKCkKICAgIHsKICAgICAgICBzdGQ6OmNvdXQgPDwgX19QUkVUVFlfRlVOQ1RJT05fXyA8PCBzdGQ6OmVuZGw7CiAgICB9Cn07CgpjbGFzcyBEZXJpdmVPbmUgOiBwdWJsaWMgQmFzZQp7CnB1YmxpYzoKICAgIERlcml2ZU9uZSgpCiAgICB7CiAgICAgICAgc3RkOjpjb3V0IDw8IF9fUFJFVFRZX0ZVTkNUSU9OX18gPDwgc3RkOjplbmRsOwogICAgfQp9OwoKY2xhc3MgRGVyaXZlVHdvIDogcHVibGljIEJhc2UKewpwdWJsaWM6CiAgICBEZXJpdmVUd28oKQogICAgewogICAgICAgIHN0ZDo6Y291dCA8PCBfX1BSRVRUWV9GVU5DVElPTl9fIDw8IHN0ZDo6ZW5kbDsKICAgIH0KfTsKCmNsYXNzIERlcml2ZVRocmVlIDogcHVibGljIERlcml2ZVR3bwp7CnB1YmxpYzoKICAgIERlcml2ZVRocmVlKCkKICAgIHsKICAgICAgICBzdGQ6OmNvdXQgPDwgX19QUkVUVFlfRlVOQ1RJT05fXyA8PCBzdGQ6OmVuZGw7CiAgICB9Cn07Ci8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgoKaW50IG1haW4oaW50IGFyZ2MsIGNoYXIgKmFyZ3ZbXSkKewogICAgRmFjdG9yeTxCYXNlLCBEZXJpdmVPbmUsIERlcml2ZVR3bywgRGVyaXZlVGhyZWU+IGYxOwogICAgCiAgICBmb3IgKHN0ZDo6c2l6ZV90IGk9MDsgaTxmMS5zaXplKCk7ICsraSkKICAgIHsKICAgICAgICBCYXNlICpwID0gZjEuZ2V0KGkpOwogICAgICAgIGRlbGV0ZSBwOwogICAgfQoKICAgIHJldHVybiBFWElUX1NVQ0NFU1M7Cn0=