|
Boost : |
Subject: [boost] Picking overload with the most specific concept
From: Louis Dionne (louis.dionne92_at_[hidden])
Date: 2013-02-10 23:28:28
Hi,
I was playing around today and I achieved to do something I find quite cool.
I would like to know whether the technique/general principle is of any
interest. Basically, it allows to overload functions based on the modeling of
a concept by a type without having to write complicated enable_ifs. It does
come with some problems and it is not very general for the moment, but it's a
first shot. Here we go:
#include <duck.hpp> // the library where I implemented that
#include <forward_list>
#include <utility>
#include <vector>
// Generates some boilerplate required to enable concept overloading for
// a function named `my_distance`. Ignore this for now.
DUCK_ENABLE_CONCEPT_OVERLOADING(
my_distance,
my_distance(std::declval<Iterator>(), std::declval<Iterator>(), State()),
typename Iterator
)
struct random_access_version_picked { };
struct forward_version_picked { };
// The State template parameter will be used to carry information during
// the resolution. tag::my_distance was defined by the above macro.
template <typename Iterator, typename State = tag::my_distance>
// This can be seen like an enable_if with some more functionality.
typename duck::requires<
// This overload is picked iff Iterator models RandomAccessIterator
// and no other overload for a more specific concept exist.
// Concepts are MPL metafunction classes, so there's no magic here.
duck::model_of<duck::RandomAccessIterator, Iterator>
// Could add more duck::model_of clauses here
, duck::overload_resolution_state<State> // required for the mechanics
, duck::template_parameters<Iterator> // ditto
, random_access_version_picked>::type // return type
my_distance(Iterator, Iterator, State = State()) {
return random_access_version_picked();
}
// Same thing for the ForwardIterator implementation.
template <typename Iterator, typename State = tag::my_distance>
typename duck::requires<
duck::model_of<duck::ForwardIterator, Iterator>
, duck::overload_resolution_state<State>
, duck::template_parameters<Iterator>
, forward_version_picked>::type
my_distance(Iterator, Iterator, State = State()) {
return forward_version_picked();
}
int main() {
std::forward_list<int> list;
std::vector<int> vec;
forward_version_picked forward = my_distance(begin(list), end(list));
random_access_version_picked random = my_distance(begin(vec),end(vec));
}
This example works with Clang 3.3 and GCC 4.8. For those interested in seeing
more, the full library is available at:
http://github.com/ldionne/duck
Look for the `next` branch. The file involved with the above mechanics is
include/duck/requires.hpp. Also see the test in test/requires.cpp.
Regards,
Louis Dionne
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk