syvyi writes:
What if the composite key should be parameterized from a file?
OK, this can be done, but you need to move some of the container
definition components from compile time to run time. The following
typedef std::function any_person_extractor;
defines a polymorhpic key extractor on person: something that takes
a person and return something (which we wrap in a boost::any object,
since we won't know what this something is until run time.) Similarly,
typedef std::function<
bool(const boost::any&,const boost::any&)> any_compare;
is a polymorphic wraper for compare objects taking boost::any's: each
compare objects we feed into any_compare will have to know what's inside
these boost::any's to do the proper comparison, which we can do with
template<typename T>
struct any_less
{
bool operator()(const boost::any& x,const boost::any& y)const
{
return boost::any_cast<T>(x)
struct any_less<void>
{
bool operator()(const boost::any& x,const boost::any& y)const
{return false;}
};
Now, let's define the multi_index_container instantiation as:
typedef multi_index_container<
person,
indexed_by<
ordered_non_unique<
composite_key<
person,
any_person_extractor,
any_person_extractor,
any_person_extractor,
any_person_extractor
>,
composite_key_compare<
any_compare,
any_compare,
any_compare,
any_compare
>
>
person_container;
What we are doing here is reserve 4 slots (we can have more,
of course) to fill at run time with specific key extractors (and their
corresponding compare objects.) For instance, the following
person_container c(
boost::make_tuple(
boost::make_tuple(
boost::make_tuple(
any_person_extractor(member()),
any_person_extractor(member()),
any_person_extractor(
member()),
void_person_extractor()
),
boost::make_tuple(
any_less<int>(),
any_lessstd::string(),
any_lessstd::string(),
any_less<void>()
)
)
));
instantiates a person_container with a composite key having three
extractors on birth year, name and surname (a more elaborate example
would fetch the info on which extractors toprovide from a configuration
file or something); the remainng slot we fill with our dummy key
extractor and compa object. Once instantiated, c can be used as a normal
(compile-time defined) container. for instance, the following retrieves
the persons born in 1959:
std::pair p=
c.equal_range(1959);
If the first key extractor weren't compatible with the int we've
provided, for instance if we'd passed a string, a boost:any exception
would be thrown --that's the price we pay for having this run-time
flexibility, lack of compile time type checkhing.
And that's it. You can play with a full example at
http://coliru.stacked-crooked.com/a/4fa76b314298516d
Joaquín M López Muñoz
Telefónica Digital