...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
(For the source of the examples in this section see multi.cpp)
Operations can have more than one any
argument. Let's use binary addition as an example.
typedef any< mpl::vector< copy_constructible<>, typeid_<>, addable<>, ostreamable<> > > any_type; any_type x(10); any_type y(7); any_type z(x + y); std::cout << z << std::endl; // prints 17
This is not a multimethod. The underlying types of the
arguments of +
must be the same
or the behavior is undefined. This example is correct because the arguments
both hold int
's.
Note | |
---|---|
Adding |
addable
<>
requires the types of the arguments
to be exactly the same. This doesn't cover all uses of addition though. For
example, pointer arithmetic takes a pointer and an integer and returns a pointer.
We can capture this kind of relationship among several types by identifying
each type involved with a placeholder. We'll let the placeholder _a
represent the pointer and the placeholder
_b
represent the integer.
int array[5]; typedef mpl::vector< copy_constructible<_a>, copy_constructible<_b>, typeid_<_a>, addable<_a, _b, _a> > requirements;
Our new concept, addable<_a, _b, _a>
captures the rules of pointer addition: _a
+ _b -> _a
.
Also, we can no longer capture the variables independently.
any<requirements, _a> ptr(&array[0]); // illegal
This doesn't work because the library needs to know the type that _b binds
to when it captures the concept bindings. We need to specify the bindings of
both placeholders when we construct the any
.
typedef mpl::map<mpl::pair<_a, int*>, mpl::pair<_b, int> > types; any<requirements, _a> ptr(&array[0], make_binding<types>()); any<requirements, _b> idx(2, make_binding<types>()); any<requirements, _a> x(ptr + idx); // x now holds array + 2
Now that the arguments of +
aren't
the same type, we require that both arguments agree that _a
maps to int*
and that _b
maps to int
.
We can also use tuple
to avoid having to write out the map out explicitly. tuple
is just a convenience class that combines the placeholder bindings it gets
from all its arguments.
tuple<requirements, _a, _b> t(&array[0], 2); any<requirements, _a> y(get<0>(t) + get<1>(t));