#include <iostream>
#include <memory>
#include <tuple>
struct Base { };
struct A : Base { A(int) {} ~A() { std::cout << "~A\n"; } };
struct B : Base { B(int) {} ~B() { std::cout << "~B\n"; } };
struct C : Base { C(int) {} ~C() { std::cout << "~C\n"; } };
template<int... Is>
struct indices { typedef indices type; };
template<int N, int... Is>
struct make_indices : make_indices<N - 1, N - 1, Is...> { };
template<int... Is>
struct make_indices<0, Is...> : indices<Is...> { };
template<typename... Types>
struct Factory
{
typedef std::tuple<Types...> TypesTuple;
std::shared_ptr<Base> operator()(int const index)
{
return produce(index);
}
std::shared_ptr<Base> produce(int const index)
{
return produce_impl(make_indices<sizeof...(Types)>(), index);
}
template<int I, int... Is>
std::shared_ptr<Base> produce_impl(indices<I, Is...>, int const index)
{
if (I == index) {
return std::make_shared<typename std::tuple_element<I, TypesTuple>::type>(42);
}
return produce_impl(indices<Is...>(), index);
}
std::shared_ptr<Base> produce_impl(indices<>, int const index)
{
throw "Uh-oh!";
}
};
int main()
{
Factory<A, B, C> fac;
fac(0);
fac(1);
fac(2);
fac(3); // cause exception.
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bWVtb3J5PgojaW5jbHVkZSA8dHVwbGU+CgpzdHJ1Y3QgQmFzZSB7IH07CnN0cnVjdCBBIDogQmFzZSB7IEEoaW50KSB7fSB+QSgpIHsgc3RkOjpjb3V0IDw8ICJ+QVxuIjsgfSB9OwpzdHJ1Y3QgQiA6IEJhc2UgeyBCKGludCkge30gfkIoKSB7IHN0ZDo6Y291dCA8PCAifkJcbiI7IH0gfTsKc3RydWN0IEMgOiBCYXNlIHsgQyhpbnQpIHt9IH5DKCkgeyBzdGQ6OmNvdXQgPDwgIn5DXG4iOyB9IH07Cgp0ZW1wbGF0ZTxpbnQuLi4gSXM+CnN0cnVjdCBpbmRpY2VzIHsgdHlwZWRlZiBpbmRpY2VzIHR5cGU7IH07Cgp0ZW1wbGF0ZTxpbnQgTiwgaW50Li4uIElzPgpzdHJ1Y3QgbWFrZV9pbmRpY2VzIDogbWFrZV9pbmRpY2VzPE4gLSAxLCBOIC0gMSwgSXMuLi4+IHsgfTsKCnRlbXBsYXRlPGludC4uLiBJcz4Kc3RydWN0IG1ha2VfaW5kaWNlczwwLCBJcy4uLj4gOiBpbmRpY2VzPElzLi4uPiB7IH07Cgp0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBUeXBlcz4Kc3RydWN0IEZhY3RvcnkKewogICAgdHlwZWRlZiBzdGQ6OnR1cGxlPFR5cGVzLi4uPiBUeXBlc1R1cGxlOwoKICAgIHN0ZDo6c2hhcmVkX3B0cjxCYXNlPiBvcGVyYXRvcigpKGludCBjb25zdCBpbmRleCkKICAgIHsKICAgICAgICByZXR1cm4gcHJvZHVjZShpbmRleCk7CiAgICB9CgogICAgc3RkOjpzaGFyZWRfcHRyPEJhc2U+IHByb2R1Y2UoaW50IGNvbnN0IGluZGV4KQogICAgewogICAgICAgIHJldHVybiBwcm9kdWNlX2ltcGwobWFrZV9pbmRpY2VzPHNpemVvZi4uLihUeXBlcyk+KCksIGluZGV4KTsKICAgIH0KCiAgICB0ZW1wbGF0ZTxpbnQgSSwgaW50Li4uIElzPgogICAgc3RkOjpzaGFyZWRfcHRyPEJhc2U+IHByb2R1Y2VfaW1wbChpbmRpY2VzPEksIElzLi4uPiwgaW50IGNvbnN0IGluZGV4KQogICAgewogICAgICAgIGlmIChJID09IGluZGV4KSB7CiAgICAgICAgICAgIHJldHVybiBzdGQ6Om1ha2Vfc2hhcmVkPHR5cGVuYW1lIHN0ZDo6dHVwbGVfZWxlbWVudDxJLCBUeXBlc1R1cGxlPjo6dHlwZT4oNDIpOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHByb2R1Y2VfaW1wbChpbmRpY2VzPElzLi4uPigpLCBpbmRleCk7CiAgICB9CgogICAgc3RkOjpzaGFyZWRfcHRyPEJhc2U+IHByb2R1Y2VfaW1wbChpbmRpY2VzPD4sIGludCBjb25zdCBpbmRleCkKICAgIHsKCQl0aHJvdyAiVWgtb2ghIjsKICAgIH0KfTsKCmludCBtYWluKCkKewoJRmFjdG9yeTxBLCBCLCBDPiBmYWM7CglmYWMoMCk7CglmYWMoMSk7CglmYWMoMik7CglmYWMoMyk7IC8vIGNhdXNlIGV4Y2VwdGlvbi4KfQo=