Reasoning about boost mpl placeholders - c++

The Tutorial: Metafunctions and Higher-Order Metaprogramming section of the Boost MPL library documentation states that transform can be invoked like so
typename mpl::transform<D1,D2, mpl::minus<_1,_2> >::type
where the placeholders _1 and _2 signify that when the transform's BinaryOperation is invoked, its first and second arguments will be passed on to minus in the positions indicated by _1 and _2, respectively.
I've been reading this over and over again for almost a month and I still don't understand it.
What values exactly do the placeholders _1 and _2 have? D1 and D2? If so, why not write mpl::minus<D1,D2>? Also considering that the placeholders are defined as typedef arg<1> _1; and typedef arg<2> _2; and consequently the original expression in my mind amounts to
typename mpl::transform<D1,D2, mpl::minus<<arg<1>,<arg<2> > >::type
I'm sure I'm thinking about placeholders the wrong way. I'd appreciate some guidance here.

Indeed, you're thinking about placeholders the wrong way.
mpl::minus is a template in MPL's metalanguage that symbolically represents (or corresponds to) a certain high-level behavior, namely, subtraction. You're thinking of it as if it's a non-meta construct such as a function
int minus(int a, int b) { return a - b; }
but it's not. (The standard C++11 library does have something kind of like that, called std::minus<>, but that's not what mpl::minus does!)
mpl::minus represents the subtraction operation at a higher level of abstraction. Don't worry for another couple of paragraphs about how mpl::minus is implemented. Just think about what it represents, which is subtraction of two things.
Ah, but which two things? Well, mpl::minus lets you specify those things as template parameters. For example,
mpl::minus<mpl::int_<7>, mpl::int_<3>>
expands to a type whose member typedef type is the same as mpl::int_<4>.
Okay, but in the dimensional analysis example from Boost, they don't have just two things; they have sequences D1 and D2 of dimensions. (This is a very important point!) Subtracting sequences isn't the same thing as subtracting integers; consider
auto a = std::vector<int>{ 1, 0, 0 };
auto b = std::vector<int>{ 0, 1, 0 };
auto c = (a - b); // Won't compile!
Likewise, in the meta space,
using a = mpl::vector<mpl::int_<1>, mpl::int_<0>, mpl::int_<0>>;
using b = mpl::vector<mpl::int_<1>, mpl::int_<0>, mpl::int_<0>>;
using c = mpl::minus<a,b>; // Won't compile!
What we mean to say, in the first case, is
auto c = std::vector<int>{};
std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(c), std::minus<>{});
and what we mean to say, in the second (meta) case, is
using c = mpl::transform<a, b, mpl::minus>::type; // caveat: we're not done yet
Notice that the C++11 std::transform takes pairs of iterators a.begin(), a.end() instead of just a; it takes b.begin() but not b.end() (a deficiency that is only now being corrected by the Committee); and it mutates c via an output iterator, rather than returning a completely new object, for efficiency. MPL's compile-time meta-version takes containers a and b directly and returns a new container c, i.e., it has value semantics, which IMHO is strictly easier to think about.
So, the above is all correct, EXCEPT for one tiny detail! mpl::transform is actually a very generic algorithm, which means that it expects you to spell out the details of the transformation. You said "mpl::minus", which means "subtract", okay, but subtract what from what? Subtract the elements of the first sequence from elements of the second? Subtract the second's elements from the first? Subtract 42 from the elements of the second sequence and toss out the first one entirely?
Well, we mean "subtract the second sequence's elements, element-wise, from the first's." Which we write as
using c = mpl::transform<a, b, mpl::minus<_1, _2>>::type;
We could equally well write
using c = mpl::transform<b, a, mpl::minus<_2, _1>>::type;
— it would mean the exact same thing.
This generic transform algorithm lets us write complicated transforms such as
// hide some irrelevant boilerplate behind an alias
template<typename... Ts>
using multiplies_t = mpl::multiplies<Ts...>::type;
// compute c = a^2 + 2ab + 1
using c = mpl::transform<a, b,
mpl::plus<multiplies_t< _1, _1 >, // a^2 ...
multiplies_t< mpl::int_<2>, _1, _2 >, // ... + 2ab ...
mpl::int_<1>> // ... + 1
>::type;
Here we can refer to the same element of sequence a three times, using the symbol _1, while _2 refers to the corresponding element of sequence b.
So, that's the point of the symbols _1 and _2 in the context of mpl::transform. But you're probably still wondering how they're implemented. Well, there's no magic here. They might as well be implemented as
template<int> struct _ {};
using _1 = _<1>;
using _2 = _<2>;
As long as they get unique, distinguishable entities in C++'s type system, that's all MPL really cares about.
But in fact they're actually implemented as typedefs for specializations of mpl::arg, which leads to a nifty trick. Since _1 is a synonym for mpl::arg<1>, we can say
_1::apply<A,B,C>::type is the same type as A
_2::apply<A,B,C>::type is the same type as B
...
and I would guess that mpl::transform is able to take advantage of that fact internally.

Related

Is there an existing name for this type and function?

There are 2 hard problems in computer science: cache invalidation, naming things and off-by-one errors.
This is about the 2nd problem: naming things.
I'm looking if this technique or type has been used somewhere else already and has a name. dichotomy is an ok name, but bools_at_compile_time is a horrible one.
using dichotomy_t = std::variant<std::false_type, std::true_type>;
// (or a struct that inherits from that, and overloads operator bool())
constexpr dichotomy_t dichotomy( bool b ) {
if (b) return std::true_type{};
return std::false_type{};
}
template<class F, class...Bools>
constexpr auto bools_at_compile_time( F&& f, Bools...bools ) {
static_assert( (std::is_same<Bools, bool>{} && ...) );
return std::visit( std::forward<F>(f), dichotomy(bools)... );
}
dichotomy_t is a variant between true and false. Its runtime representation is 0 or 1.
What this lets you do is:
auto foo( bool x, bool y ) { // <-- x and y are run-time bools here
auto func = [&](auto x, auto y) {
return some_template<x,y>(); // <-- x and y are compile-time bools here
};
return bools_at_compile_time( func, x, y ); // <-- converts runtime to compile time bools
}
Is there a name for dichotomy_t or the more general bools_at_compile_time technique? I'm looking for a name that is well known in any community (even a non-C++ one), even a verb that describes "taking a runtime value and creating a switch and a set of compile time value in generated code to pick between" better than a sentence.
Live example
A good answer would include the name, citations/quotes describing what that name means, examples of that named thing in use in the other context, and evidence that this name is equivalent to or inclusive of the above type/value and function.
(It may help to find a name the generalization of this would be an enum instead of a bool, which has a fixed number of known states, and a switch/case map that converts the runtime value into a compile-time constant in each case clause.)
I do not know of any existing names for this pattern, but if you take a good look at how the STL is naming things, you can use name close enough to make your code explicit.
I also liked the dispatcher_t idea from #Jarod42 , I think it is more generic than dichotomy_t or n_chotomy_t.
dichotomy() could be called make_variant(b). Since it will return the std::variant value of a boolean given in argument. Much like std::make_tuple makes a tuple from multiple arguments.
I would suggest to replace bools_at_compile_time by static_eval. Much like static_assert makes an assertion at compile time.
Not that if eval is not the correct adjective for your use case you can easily adapt it static_*.
#include <type_traits>
#include <variant>
#include <utility>
using dichotomy_t = std::variant<std::false_type, std::true_type>;
// (or a struct that inherits from that, and overloads operator bool())
constexpr dichotomy_t make_variant( bool b ) {
if (b) return std::true_type{};
return std::false_type{};
}
template<class F, class...Bools>
constexpr auto static_eval( F&& f, Bools...bools ) {
static_assert( (std::is_same<Bools, bool>{} && ...) );
return std::visit( std::forward<F>(f), make_variant(bools)... );
}
template<bool x, bool y>
auto some_template() {
return x || y;
}
auto foo( bool x, bool y ) { // <-- x and y are run-time bools here
auto func = [&](auto x, auto y) {
return some_template<x,y>(); // <-- x and y are compile-time bools here
};
return static_eval( func, x, y ); // <-- converts runtime to compile time bools
}
#include <iostream>
int main() {
std::cout << foo( true, true ) << "\n";
}
Generation of specialized version of a function is called cloning. (see Procedure Cloning). The term clone is used to name the specialized function generated by the optimizer during constant propagation (see gcc doc).
The set of specialized functions generated by std::visit could be named clone set.
This set is generated for all combinations of argument value. This term combination let us suppose that the set of possible value of each argument is finite.
So we could have a long name for the set of clones such as, set of clones for all combination of argument values. An other option more obscure but shorter could be combinatorial clone set.
As already pointed out, the action of selecting the right function to call in term of the argument could be called dispatch.
So I would propose combinatiorial_clone_set_dispatch or dispatch_in_combinatorial_clone_set ...
As I am unaware of a similar implementation, I'll just go type by type with bikeshed colors.
using boolean_t = std::variant<std::false_type, std::true_type>;
This is pretty self-explanatory, as it's a variant that can store one or the other of the std::integral_constants for true or false. It's kind of a bool, but bool_t is likely to cause confusion. An alternative is boolean_variant, but that may be too verbose.
constexpr boolean_t to_boolean_t( bool b ) {
if (b) return std::true_type{};
return std::false_type{};
}
I started with convert_bool, but that's a bit too generic. to_boolean_t is more expressive. make_boolean_t is also a possibility, as it is basically a boolean_t factory function. Note: I previously chose to_constexpr_boolean, but that's unnecessarily verbose.
template<class F, class...Bools>
constexpr auto static_eval( F&& f, Bools...bools ) {
static_assert( (std::is_same<Bools, bool>{} && ...) );
return std::visit( std::forward<F>(f), to_boolean_t(bools)... );
}
I chose static_eval here as I like Clonk's reasoning, but "static" has contextual meaning in C++, so alternatives are (in no order of importance):
boolean_visit
static_visit
constexpr_eval
constexpr_visit
You issue was: (bold mine)
I'm looking for a name that is well known in any community (even a
non-C++ one), even a verb that describes "taking a runtime value and
creating a switch and a set of compile time value in generated code to
pick between" better than a sentence.
There is, but only if you will adopt it from a related field of science:
The U.S. National Electrical Code (NEC) defines a switchboard as "a
large single panel, frame, or assembly of panels on which are mounted,
on the face, back, or both, switches, over-current and other
protective devices, buses, and usually instruments". The role of a
switchboard is to allow the division of the current supplied to the
switchboard into smaller currents for further distribution and to
provide switching, current protection and (possibly) metering for
those various currents. In general, switchboards may distribute power
to transformers, panelboards, control equipment, and, ultimately, to
individual system loads.
Adopting this thinking, you would simply call it switches.
I will also add that it is quite unusual to specify (ie. repeat) the storage type or cv-qualifier, etc. in type/variable names - even when not directly visible you would usually leave that as implicit - unless it really needs to be emphasized.
Maybe staticCastValue?
As in you are casting a dynamic(runtime) value to a static value.
Can be used with templates or overloads for different types.
Or maybe assertInmutable?
As in you are converting a mutable type into an inmutable one.
Or perhaps expressConstantly?
As in you are expressing the same value but in constant form.
A form similar to constexpr.
A wild one:
staticBifurcate?
As in theres two things to choose from, thus a bifurcation is there.
bifurcate
verb
/ˈbʌɪfəkeɪt/
1.
divide into two branches or forks.
"just below Cairo the river bifurcates"
Or finally convertToConstExpr?
Explicitly saying that the value will be converted to something akin or compatible with a constexpr.

Why is `boost::hana::range_c` not a Sequence?

#include <string>
#include <utility>
#include <vector>
#include <boost/hana.hpp>
namespace hana = boost::hana;
template <typename ...T>
void indexed_T_work(T&& ...args)
{
auto indices = hana::range_c<std::size_t, 0, sizeof...(T)>;
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::for_each(
hana::zip(indices, types)
, [](auto&& pair_) { /* Do index-dependent work with each `T` */ }
);
}
int main()
{
indexed_T_work(5, 13, std::vector<std::string>{}, 32.f, 42, "foo");
}
I'd like to use hana::zip on a hana::tuple and hana::range_c, but hana::range_c is not considered a Sequence, which is a requirement for hana::zip. What is the reasoning behind this decision? How can I (idiomatically) accomplish my goal while respecting that decision?
First, there are several solutions:
Solution 1
auto indices = hana::to<hana::tuple_tag>(hana::range_c<std::size_t, 0, sizeof...(T)>);
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::for_each(hana::zip(indices, types), hana::fuse([](auto i, auto&& x) {
// ...
}));
Solution 2
auto indices = hana::range_c<std::size_t, 0, sizeof...(T)>;
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::for_each(indices, [&](auto i) {
auto& x = types[i];
// ...
});
Solution 3
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::size_c<sizeof...(T)>.times.with_index([&](auto i) {
auto& x = types[i];
// ...
});
Solution (1) has the disadvantage of making a copy of each args because zip returns a sequence of sequences, and everything in Hana is by value. Since this is probably not what you want, you should pick whichever you prefer between solutions (2) and (3), which are really equivalent.
Now, the reason why ranges do not model the Sequence concept is because that wouldn't make sense. The Sequence concept requires that we be able to create an arbitrary Sequence using the hana::make function. Hence, for any Sequence tag S, hana::make<S>(...) must create a Sequence of tag S that contains .... However, a range must contain contiguous integral_constants in some interval. Hence, if range was a Sequence, hana::make<hana::range_tag>(...) should contain whatever ... is, which breaks the invariant of a range if ... are not contiguous integral_constants. Consider for example
hana::make<hana::range_tag>(hana::int_c<8>, hana::int_c<3>,
hana::int_c<5>, hana::int_c<10>)
This should be a range containing integral_constants 8,3,5,10, which does not make sense. Another similar example showing why a range can't be a Sequence is the permutations algorithm. The permutations algorithm takes a Sequence and returns a Sequence of Sequences containing all the permutations. Clearly, since a range can only hold integral_constants, it does not make sense to try and create a range of ranges. Examples like this abound.
In other words, ranges are too specialized to model the Sequence concept. The upside of having such a specialized structure is that it's very compile-time efficient. The downside is that it's not a general-purpose container and some operations can't be done on it (like zip). However, you can totally take a range and convert it to a full-blown sequence, if you know what the tradeoff is.

map/fold operators (in c++)

I am writing library which can do map/fold operations on ranges. I need to do these with operators. I am not very familiar with functional programming and I've tentatively selected * for map and || for fold. So to find (brute force algorithm) maximum of cos(x) in interval: 8 < x < 9:
double maximum = ro::range(8, 9, 0.01) * std::cos || std::max;
In above, ro::range can be replaced with any STL container.
I don't want to be different if there is any convention for map/fold operators. My question is: is there a math notation or does any language uses operators for map/fold?
** EDIT **
For those who asked, below is small demo of what RO currently can do. scc is small utility which can evaluate C++ snippets.
// Can print ranges, container, tuples, etc directly (vint is vector<int>) :
scc 'vint V{1,2,3}; V'
{1,2,3}
// Classic pipe. Alogorithms are from std::
scc 'vint{3,1,2,3} | sort | unique | reverse'
{3, 2, 1}
// Assign 42 to [2..5)
scc 'vint V=range(0,9); range(V/2, V/5) = 42; V'
{0, 1, 42, 42, 42, 5, 6, 7, 8, 9}
// concatenate vector of strings ('add' is shotcut for std::plus<T>()):
scc 'vstr V{"aaa", "bb", "cccc"}; V || add'
aaabbcccc
// Total length of strings in vector of strings
scc 'vstr V{"aaa", "bb", "cccc"}; V * size || (_1+_2)'
9
// Assign to c-string, then append `"XYZ"` and then remove `"bc"` substring :
scc 'char s[99]; range(s) = "abc"; (range(s) << "XYZ") - "bc"'
aXYZ
// Remove non alpha-num characters and convert to upper case
scc '(range("abc-123, xyz/") | isalnum) * toupper'
ABC123XYZ
// Hide phone number:
scc "str S=\"John Q Public (650)1234567\"; S|isdigit='X'; S"
John Q Public (XXX)XXXXXXX
This is really more a comment than a true answer, but it's too long to fit in a comment.
At least if my memory for the terminology serves correctly, map is essentially std::transform, and fold is std::accumulate. Assuming that's correct, I think trying to write your own would be ill-advised at best.
If you want to use map/fold style semantics, you could do something like this:
std::transform(std::begin(sto), std::end(sto), ::cos);
double maximum = *std::max_element(std::begin(sto), std::end(sto));
Although std::accumulate is more like a general-purpose fold, std::max_element is basically a fold(..., max); If you prefer a single operation, you could do something like:
double maximum = *(std::max_element(std::begin(sto), std::end(sto),
[](double a, double b) { return cos(a) < cos(b); });
I urge you to reconsider overloading operators for this purpose. Either example I've given above should be clear to almost any reasonable C++ programmer. The example you've given will be utterly opaque to most.
On a more general level, I'd urge extreme caution when overloading operators. Operator overloading is great when used correctly -- being able to overload operators for things like arbitrary precision integers, matrices, complex numbers, etc., renders code using those types much more readable and understandable than code without overloaded operators.
Unfortunately, when you use operators in unexpected ways, precisely the opposite is true -- and these uses are certainly extremely unexpected -- in fact, well into the range of "quite surprising". There might be question (but at least a little justification) if these operators were well understood in specific areas, but contrary to other uses in C++. In this case, however, you seem to be inventing a notation "out of whole cloth" -- I'm not aware of anybody using any operator C++ supports overloading to mean either fold or map (nor anything visually similar or analogous in any other way). In short, using overloading this way is a poor and unjustified idea.
Of the languages I know, there is no standard way for folding. Scala uses operators /: and :\ as well as metthod names, Lisp has reduce, Haskell has foldl.
map on the other hand is more common to find simply as map in all the languages I know.
Below is an implementation of fold in quasi-human-readable infix C++ syntax. Note that the code is not very robust and only serves to demonstrate the point. It is made to support the more usual 3-argument fold operators (the range, the binary operation, and the neutral element).
This is easily the funnies way to abuse (have you just said "rape"?) operator overloading, and one of the best ways to shoot yourself in the foot with a 900 pound artillery shell.
enum { fold } fold_t;
template <typename Op>
struct fold_intermediate_1
{
Op op;
fold_intermediate_1 (Op op) : op(op) {}
};
template <typename Cont, typename Op, bool>
struct fold_intermediate_2
{
const Cont& cont;
Op op;
fold_intermediate_2 (const Cont& cont, Op op) : cont(cont), op(op) {}
};
template <typename Op>
fold_intermediate_1<Op> operator/(fold_t, Op op)
{
return fold_intermediate_1<Op>(op);
}
template <typename Cont, typename Op>
fold_intermediate_2<Cont, Op, true> operator<(const Cont& cont, fold_intermediate_1<Op> f)
{
return fold_intermediate_2<Cont, Op, true>(cont, f.op);
}
template <typename Cont, typename Op, typename Init>
Init operator< (fold_intermediate_2<Cont, Op, true> f, Init init)
{
return foldl_func(f.op, init, std::begin(f.cont), std::end(f.cont));
}
template <typename Cont, typename Op>
fold_intermediate_2<Cont, Op, false> operator>(const Cont& cont, fold_intermediate_1<Op> f)
{
return fold_intermediate_2<Cont, Op, false>(cont, f.op);
}
template <typename Cont, typename Op, typename Init>
Init operator> (fold_intermediate_2<Cont, Op, false> f, Init init)
{
return foldr_func(f.op, init, std::begin(f.cont), std::end(f.cont));
}
foldr_func and foldl_func (the actual algorithms of left and right folds) are defined elsewhere.
Use it like this:
foo myfunc(foo, foo);
container<foo> cont;
foo zero, acc;
acc = cont >fold/myfunc> zero; // right fold
acc = cont <fold/myfunc< zero; // left fold
The word fold is used as a kind of poor man's new reserved word here. One can define several variations of this syntax, including
<<fold/myfunc<< >>fold/myfunc>>
<foldl/myfunc> <foldr/myfunc>
|fold<myfunc| |fold>myfunc|
The inner operator must have the same or greater precedence as the outer one(s). It's the limitation of C++ grammar.
For map, only one intermediate is needed and the syntax could be e.g.
mapped = cont |map| myfunc;
Implementing it is a simple exercise.
Oh, and please don't use this syntax in production, unless you know very well what you are doing, and probably even if you do ;)

Mapping combination of 4 integers to a single value

I have 4 separate integers that need to be mapped to an arbitrary, constant value.
For example, 4,2,1,1 will map to the number 42
And the number 4,2,1,2 will map to the number 86.
Is there anyway I can achieve this by using #define's or some sort of std::map. The concept seems very simple but for some reason I can't think of a good, efficient method of doing it. The methods I have tried are not working so I'm looking for some guidence on implementation of this.
Will a simple function suffice?
int get_magic_number( int a, int b , int c, int d)
{
if( (a==4)&&(b==2)&&(c==1)&&(d==1) ) return 42;
if( (a==4)&&(b==2)&&(c==1)&&(d==2) ) return 86;
...
throw SomeKindOfError();
}
Now that may look ugly, but you can easily create a macro to pretty it up. (Or a helper class or whatever... I'll just show the macro as I think its easy.
int get_magic_number( int a, int b , int c, int d)
{
#DEFINE MAGIC(A,B,C,D,X) if((a==(A))&&(b==(B))&&(c==(C))&&(d==(D))) return (X);
MAGIC(4,2,1,1, 42);
MAGIC(4,2,1,2, 86);
...
#UNDEF MAGIC
throw SomeKindOfError();
}
If you really care you can probably craft a constexpr version of this too, which you'll never be able to do with std::map based solutions.
Utilize a std::map<std::vector<int>, int>, so that the vector containing {4,2,1,1} will have the value 42, and so on.
Edit: I agree std::tuple would be a better way to go if you have a compiler with C++11 support. I used a std::vector because it is arguably more portable at this stage. You could also use a std::array<int, 4>.
If you do not have access to boost::tuple, std::tuple or std::array, you can implement a type holding 4 integers with a suitable less-than comparison satisfying strict weak ordering:
struct FourInts {
int a,b,c,d;
FourInts() : a(), b(), c(), d() {}
bool operator<(const FourInts& rhs) const {
// implement less-than comparison here
}
};
then use an std::map:
std::map<FourInts, int> m;
If you organise your ints in an array of standard library container, you can use std::lexicographical_compare for the less-than comparison.
If you know there's always 4 integers mapped to 1 integer I suggest you go with:
std::map< boost::tuple<int, int, int, int>, int >
Comparison (lexicographical) is already defined for tuples.

Generating permutations via templates

I'd like a function, or function object, that can generate a permutation of its inputs with the permutation specified at compile time. To be clear, I am not looking to generate all of the permutations, only a specific one. For instance, permute<1,4,3,2>( a, b, c, d ) would return (a,d,c,b). Obviously, it is straightforward to do this with a permutation of a specific length, e.g. 2, like this
#include <boost/tuple.hpp>
template< unsigned a, unsigned b>
struct permute {
template< class T >
boost::tuple< T, T > operator()( T ta, T tb ) {
boost::tuple< T, T > init = boost::make_tuple( ta, tb );
return boost::make_tuple( init.get< a >(), init.get< b >() );
}
};
But, how would I go about doing this for an arbitrary length permuation? Also, is there a cleaner way of writing the above code? Yes, the above code is not restricted to making permutations as permute<2,2>(a,b) is allowed, but I don't see that as a flaw. However, can it be restricted to only allowing actual permutations?
C++0x provides variadic templates, which you should be able to use to handle an arbitrary length permutation. They were added specifically because the current version of C++ doesn't have a clean way of dealing with this kind of problem.