When working with a small template, we can get the factory function before:
i_value* make_empty_value(tag tag_type) { static constexpr auto factory = make_factory(all_tags()); auto index = std::size_t(tag_type - tag::first); if (index < tag::ntags) { return memory_manager::instance().add(factory[index]()); } else { return nullptr; } }
Full code below.
The i_value generator map is created at compile time, which allows you to search for a constant search.
:
the values in the enumeration must be sequential, but they must not start from zero.
this demonstration requires C ++ 14. It can be easily adapted to work with C ++ 11. For C ++ 03 we want to achieve an increase in mpl or boost_pp.
full working example:
#include <array> #include <utility> #include <deque> #include <iostream> // minimal implementation of virtual base class i_value { public: virtual void prove() const = 0; virtual ~i_value() = default; }; // tag enum - note that we have supplied some extra introspection information // these could just as well be constexpr integers outside the enum enum tag { ble, chn, blk, seq, first = ble, // first available tag last = seq, // last available tag ntags = last-first // number of tags }; /// Function to offset an index sequence by the distance from /// zero to the first available tag - in case the first tag is not zero template<std::size_t...tags> constexpr auto tag_offset(std::index_sequence<tags...>) { return std::index_sequence<(tags + tag::first)...>(); } /// Function to compute an index sequence of all valid tags constexpr auto all_tags() { return tag_offset(std::make_index_sequence<std::size_t(ntags)>()); } /// Factory function to generate a derived class for a given tag template <tag tag_type> class t_value : public i_value { void prove() const override { void(std::cout << "I have tag " << tag_type << std::endl); } ~t_value() { void(std::cout << "tag " << tag_type << " destroyed" << std::endl); } }; template<tag tag_type> i_value* make_instance() { return new t_value<tag_type>(); } /// Function to generate a 'factory' - an array of factory functions, one for /// each tag in the variadic template argument tags... /// Note that the array is zero-based, the tags may not be. All we care about /// here is the size of the list of tags (and their values) /// template<std::size_t...tags> constexpr auto make_factory(std::index_sequence<tags...>) { return std::array<i_value* (*)(), sizeof...(tags)> { &make_instance<static_cast<tag>(tags)>... }; } // minimal memory manager struct memory_manager { struct impl { i_value* add(i_value* item) { _ivalues.push_back(item); return item; }; ~impl() { for (auto i = _ivalues.rbegin() ; i != _ivalues.rend() ; ++i) { delete *i; } } std::deque<i_value*> _ivalues; }; static impl& instance() { static impl _instance = {}; return _instance; } }; // here is resulting factory function. i_value* make_empty_value(tag tag_type) { static constexpr auto factory = make_factory(all_tags()); auto index = std::size_t(tag_type - tag::first); if (index < tag::ntags) { return memory_manager::instance().add(factory[index]()); } else { return nullptr; } } // test int main() { for(auto tag_type : { tag::ble, tag::chn }) { auto pvalue = make_empty_value(tag_type); pvalue->prove(); } }
expected output:
I have tag 0 I have tag 1 tag 1 destroyed tag 0 destroyed
Richard Hodges
source share