Merge two Boost Fusion maps based on keys - c++11

I have two boost::fusion::maps that I want to merge in a certain way. For the two maps I want to generate a third that has all the keys present in both maps and the values are added if both a present. For example:
#include <boost/fusion/container/map.hpp>
namespace bfn = boost::fusion;
using namespace boost::fusion;
struct x{};
struct y{};
struct z{};
int main(){
auto m = make_map<x, y>(2, 4.3);
auto n = make_map<x>(2.);
auto l = accumulate_merge(m, n); // how this function should look like?
}
After that l will be equivalent to make_map<x, y>(2 + 2., 4.3).
I have no clue where to start. I tried to begin with join (and the eliminate duplicates but I got complicated pretty fast).
Is there a tool in Boost Fusion that can help me?
(There are lots of subtleties like what to do if for the same key the two corresponding types are different --but still addable--. But any first version will help).

I managed to come up with this version using boost::fusion::fold twice. I am not sure if it is (compile-time) optimal.
Basically, I iterate first over the first map. If the key is not in the second map the element is pushed to the result. If the key is in the second map the elements are added and the result (whatever the type is pushed to the result).
Finally, I iterate in the second map. If the key is in the first map I ignore it (because it was added in the first pass). If the key is not in the second the element is pushed to the result.
(The result is that the first map has precedence for the ordering of the key types)
There are some open issues or doubts:
1) there is a more efficient/compact way of doing this
2) I wasn't sure about the use of forward basically I used it everywhere (just in case)
3) not sure about the auto vs. decltype(auto) in the function returns.
4) The functions are not SFINAE friendly, I could add guards to generate soft errors. (For example if values cannot be added).
5) The result doesn't have any natural order, I don't know if this is a problem with the algorithm or with fold or because map don't specify an order with push_back (after all it is a map).
Comments are welcome.
Now the code:
namespace boost{
namespace fusion{
namespace detail{
template<class Map2>
struct merge1{
Map2 m2_;
template<typename MapOut, typename Pair1>
auto operator()(MapOut&& mo, Pair1&& p1) const{
return conditional_push_back(std::forward<MapOut>(mo), std::forward<Pair1>(p1), has_key<typename std::decay_t<Pair1>::first_type>(m2_));
}
template<typename MapOut, typename Pair1>
auto conditional_push_back(MapOut&& mo, Pair1&& p1, mpl_::bool_<false>) const{
return push_back(std::forward<MapOut>(mo), std::forward<Pair1>(p1));
}
template<typename MapOut, typename Pair1>
auto conditional_push_back(MapOut&& mo, Pair1&& p1, mpl_::bool_<true>) const{
return push_back(std::forward<MapOut>(mo), make_pair<typename std::decay_t<Pair1>::first_type>(p1.second + at_key<typename std::decay_t<Pair1>::first_type>(m2_)));
}
};
template<class Map2>
merge1<Map2> make_merge1(Map2&& m2){return {std::forward<Map2>(m2)};}
template<class Map1>
struct merge2{
Map1 m1_;
template<typename MapOut, typename Pair2>
auto operator()(MapOut&& mo, Pair2&& p2) const{
return conditional_push_back(std::forward<MapOut>(mo), std::forward<Pair2>(p2), has_key<typename std::decay_t<Pair2>::first_type>(m1_));
}
template<typename MapOut, typename Pair2>
auto conditional_push_back(MapOut&& mo, Pair2&& p2, mpl_::bool_<false>) const{
return push_back(std::forward<MapOut>(mo), std::forward<Pair2>(p2));
}
template<typename MapOut, typename Pair2>
auto conditional_push_back(MapOut&& mo, Pair2&& , mpl_::bool_<true>) const{
return mo;
}
};
template<class Map1>
merge2<Map1> make_merge2(Map1&& m){return {std::forward<Map1>(m)};}
}
template<class Map1, class Map2>
inline auto accumulate_merge(Map1&& m1, Map2&& m2){
return
as_map( // not completely sure this is a good idea
fold( // second map2 is checked for unpaired elements
std::forward<Map1>(m1),
fold( // first map1 takes the lead
std::forward<Map2>(m2),
make_map<>(),
detail::make_merge1(std::forward<Map1>(m1))
),
detail::make_merge2(std::forward<Map2>(m2))
)
);
}
}}
namespace bfn = boost::fusion;
using namespace boost::fusion;
struct x{};
struct y{};
struct z{};
int main(){
auto m = make_map<x, y >(2, 4.3 );
auto n = make_map< y, z>( 2 , 8.);
auto l = accumulate_merge(m, n);
assert( at_key<x>(l) == at_key<x>(m) );
assert( at_key<y>(l) == at_key<y>(m) + at_key<y>(n) );
assert( typeid(at_key<y>(l)) == typeid(at_key<y>(m) + at_key<y>(n)) );
assert( at_key<z>(l) == at_key<z>(n) );
}

Related

C++ construct a tuple from elements with indices that are NOT in a given index_sequence

I already have a template that given a tuple and an index_sequence can create a new tuple having the elements indexed by that sequence. This function template is called project
I figured if I can somehow calculate the difference of two index_sequences then I'm done: I pass to project the difference of make_index_sequence<original_tuple_t> and the given one, which is assumed sorted and unique.
Is this a good approach? Do you know how to implement this?
Here is a possible implementation.
First we'll start off with a simple trait to add a std::size_t onto the front of a std::index_sequence:
template <std::size_t First, typename Seq>
struct sequence_cat;
template <std::size_t First, std::size_t... Seq>
struct sequence_cat <First, std::index_sequence<Seq...>> {
using type = std::index_sequence<First, Seq...>;
};
//helper
template <std::size_t First, typename Seq>
using sequence_cat_t = typename sequence_cat<First, Seq>::type;
Now we'll define a trait called not_in_sequence which will recursively check the fronts of two std::index_sequences and filter off any from the first which occur in the second:
//empty first sequence
template <class First, class Second>
struct not_in_sequence {
using type = std::index_sequence<>;
};
//helper
template <class First, class Second>
using not_in_sequence_t = typename not_in_sequence<First, Second>::type;
//filter and recurse
template <std::size_t... First, std::size_t... Second,
std::size_t FirstHead, std::size_t SecondHead>
struct not_in_sequence <std::index_sequence<FirstHead, First...>,
std::index_sequence<SecondHead, Second...>> {
using seq1 = std::index_sequence<First...>;
using seq2 = std::index_sequence<Second...>;
using type =
std::conditional_t<
(FirstHead == SecondHead),
not_in_sequence_t<seq1, seq2>,
sequence_cat_t<
FirstHead,
not_in_sequence_t<seq1, sequence_cat_t<SecondHead, seq2>>
>
>;
};
//empty second sequence
template <std::size_t... First, std::size_t FirstHead>
struct not_in_sequence <std::index_sequence<FirstHead, First...>,
std::index_sequence<>> {
using type = std::index_sequence<FirstHead, First...>;
};
You can use not_in_sequence_t like so:
not_in_sequence_t<std::make_index_sequence<3>, std::index_sequence<0,2>>
//same as std::index_sequence<1>
There might be some edge-cases I've missed, but feel free to edit this as you like.
Live Demo

Creating a new tuple class by popping the last type

I tried the following code but it gives:
main.cpp:29:22: error: aggregate 'pop<std::tuple<int, char, float> > p' has incomplete type and cannot be defined
What am I missing?
template <typename T>
struct pop;
template <typename E, typename... Ts>
struct pop<tuple<Ts..., E>> {
using result = tuple<Ts...>;
};
tuple<int, char, float> t;
typename pop<decltype(t)>::result p;
If Ts... must be at the end in a type list, why does it work in this example from http://en.cppreference.com/w/cpp/language/parameter_pack:
template<class A, class B, class...C> void func(A arg1, B arg2, C...arg3)
{
container<A,B,C...> t1; // expands to container<A,B,E1,E2,E3>
container<C...,A,B> t2; // expands to container<E1,E2,E3,A,B>
container<A,C...,B> t3; // expands to container<A,E1,E2,E3,B>
}
tuple<Ts..., E> is a non-deduced context. [temp.deduct.type]/9:
If P has a form that contains <T> or <i>, then each argument Pi of the respective template argument list P is compared with the corresponding argument Ai of the corresponding template argument list of A. If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context.
That means that your partial specialization is never matched.
With C++14, one could use
template <class T, class=std::make_index_sequence<std::tuple_size<T>::value-1>>
struct pop;
template <typename Tuple, std::size_t... indices>
struct pop<Tuple, std::index_sequence<indices...>>
{
using type = std::tuple<std::tuple_element_t<indices, Tuple>...>;
};
template <typename T>
using pop_t = typename pop<T>::type;
Such that
using t = std::tuple<int, char, float>;
static_assert( std::is_same<pop_t<t>, std::tuple<int, char>>{}, "" );
Compiles.
Demo.
Ts... must be the last element of a type list if you want it to be deduced. tuple<Ts...,E> will not deduce Ts... to be all but the last, but rather never match anything.
Getting rid of the last argument is a bit tricker. live example:
#include <iostream>
#include <tuple>
#include <iostream>
namespace details {
template<class Lhs, class Rhs>
struct pop_helper;
template<template<class...>class Tup, class L0, class...Lhs, class...Rhs>
struct pop_helper<Tup<L0,Lhs...>, Tup<Rhs...>>:
pop_helper<Tup<Lhs...>, Tup<Rhs...,L0>>
{};
template<template<class...>class Tup, class L0, class...Rhs>
struct pop_helper<Tup<L0>, Tup<Rhs...>> {
using type=Tup<Rhs...>;
};
}
template <typename T>
struct pop;
template<template<class...>class Tup, class...Ts>
struct pop<Tup<Ts...>>:
details::pop_helper<Tup<Ts...>,Tup<>>
{};
template<typename T>
using pop_t=typename pop<T>::type;
std::tuple<int, char, float> t;
typedef pop_t<decltype(t)> p;
int main() {
p x = std::make_tuple( 7, 'x' );
std::cout << std::get<0>(x) << std::get<1>(x) << std::tuple_size<p>{} << "\n";
}
pop_helper moves the types over one at a time to the right hand side, until there is only one type left on the left hand side. Then it returns the right hand side type.
pop just passes the tuples over.
I used template<class...>class Tup instead of std::tuple, because why not support almost every template instead of just std::tuple?
pop_t gets rid of the annoying typename spam at point of use.
I use the inhertance-as-type-map-forwarding pattern, which saves on typing. With a type-map, the structure:
template<class X>
struct bob: foo<X> {};
can be read as bob<X> is foo<X>. The alternative is the more verbose
template<class X>
struct bob {
using type = typename foo<X>::type;
};
expanding variardic type lists is different than matching them. When it was designed, matching was kept simple in order to make compiler vendors be able to implement the feature. There may even be thorny issues beyond "it is tricky" down that path.
Another C++11 way to skin this cat:
#include <tuple>
template<class Tuple>
struct pop;
template<>
struct pop<std::tuple<>>
{
using type = std::tuple<>;
};
template<typename T1>
struct pop<std::tuple<T1>>
{
using type = std::tuple<>;
};
template<typename First, typename... Rest>
struct pop<std::tuple<First,Rest...>>
{
using type =
decltype(std::tuple_cat(
std::declval<std::tuple<First>>(),
std::declval<typename pop<std::tuple<Rest...>>::type>()));
};
// Test...
static_assert(std::is_same<pop<std::tuple<>>::type,std::tuple<>>::value,"");
static_assert(std::is_same<pop<std::tuple<int>>::type,std::tuple<>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char>>::type,std::tuple<int>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char,float>>::type,
std::tuple<int,char>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char,float,double>>::type,
std::tuple<int,char,float>>::value,"");
This is the solution I had come up with:
template <typename T>
struct pop;
template <typename E, typename... Ts>
struct pop<std::tuple<E, Ts...>> {
using type = decltype(tuple_cat(
declval<tuple<E>>(),
declval<typename pop<tuple<Ts...>>::type>()
));
};
template <typename E>
struct pop<std::tuple<E>> {
using type = std::tuple<>;
};

In C++, how to iterate array in reverse using for_each?

In C++11, using lambda/for_each, how do we iterate an array from end?
I tried the following, but both result in infinite loop:
for_each (end(A), begin(A), [](int i) {
....
});
for_each (A.rend(), A.rbegin(), [](int i) {
...
});
Any idea? Thanks.
You missed this ?
Flip your rbegin & rend
for_each (A.rbegin(), A.rend(), [](int i) {
...
});
Increasing reverse iterator moves them towards the beginning of the container
std::for_each( A.rbegin(), A.rend(), [](int i) { /*code*/ } ); is the simple solution.
I instead have written backwards which takes a sequence, extracts the begin and end iterator from it using the free begin and end functions (with std::begin and std::end using declarations nearby -- full ADL), creates reverse iterators around them, then returns a sequence with those two reverse iterators.
It is sort of neat, because you get this syntax:
for( int i : backwards(A) ) {
// code
}
which I find easier to read than std::for_each or manual for loops.
But I am a bit nuts.
Here is a minimal backwards. A full on solution handles adl and a few corner cases better.
template<class It, class C>
struct range_for_t{
It b,e;
C c; // for lifetime
It begin()const{return b;}
It end()const{return e;}
}
template<class It, class C>
range_for_t<It,C> range_for(It b,It e,C&& c){
return {std::move(b),std::move(e),std::forward<C>(c)};
}
template<class It>
range_for_t<It,int> range_for(It b,It e){
return {std::move(b),std::move(e)};
}
A simple range for range for only. Can be augmented with perfect forwarding.
Passing C as the container that may need lifetime extending. If passed as rvalue, copy is made, otherwise just reference. It is otherwise not used.
Next part is easy:
template<class It>
auto reverse_it(It it){
return std::reverse_iterator<It>(std::move(it));
}
template<class C>
auto backwards(C&&c){
using std::begin; using std::end;
auto b=begin(c), e=end(c);
return range_for(
reverse_it(e),reverse_it(b),
std::forward<C>(c)
);
}
That is untested but should work.
One important test is ensuring it works when you feed an rvalue vec like:
for(auto x:backwards(make_vec()))
works -- that is what the mess around storing C is about. It also assumes that moved container iterators have iterators who behave nicely.
Boost offers a feature named reversed, that can be used with C++ 11 range based for loop as describes Yakk in his answer:
for(int i : reverse(A))
{
// code
}
or
for(int i : A | reversed)
{
// code
}
Since C++20, there is a convenient adaptor for this:
#include <ranges>
...
for (auto& element: container | std::views::reverse)
For example:
#include <iostream>
#include <ranges>
#include <vector>
int main()
{
std::vector<int> container {1, 2, 3, 4, 5};
for (const auto& elem: container | std::views::reverse )
{
std::cout << elem << ' ';
}
}
// Prints 5 4 3 2 1
Try it here:
https://coliru.stacked-crooked.com/a/e320e5eec431cc87

What is the difference between project and subrange functions in boost::number::ublas?

Ie, is there any difference between
subrange(V, 0, 3);
and
project(V, range(0,3));
?
I ask because I'm digging into some code that seems to use both forms (with no apparent rhyme/reason for one vs. the other), but I can't see any difference between the two... just wanted to check to make sure I'm not missing something.
Looked into it, and I've confirmed there is no difference - subrange is simply an easy wrapper for a common-case of project, and in these cases:
subrange(V, 0, 3);
project(V, range(0,3));
...they end up identical. So using either should be fine, as long as you're consistent!
For the more curious... subrange does:
template<class V>
vector_range<V> subrange (V &data, typename V::size_type start, typename V::size_type stop) {
typedef basic_range<typename V::size_type, typename V::difference_type> range_type;
return vector_range<V> (data, range_type (start, stop));
}
while project does:
template<class V>
vector_range<V> project (V &data, typename vector_range<V>::range_type const &r) {
return vector_range<V> (data, r);
}
..and since vector_range::range_type is defined to be
typedef basic_range<size_type, difference_type> range_type;
...ie, exactly what is used in subrange, the two forms are identical.

Template type deduction problem

I've got a variant class. It has a pair of constructors:
/// Construct and fill.
template <typename T>
inline
variant (const T& t)
{
YYASSERT (sizeof (T) <= S);
new (buffer.raw) T(t);
}
template <typename T>
inline
variant (T&& t)
{
YYASSERT (sizeof (T) <= S);
new (buffer.raw) T(std::move(t));
}
Now I've called those constructors in this code:
parser::symbol_type
parser::make_IDENTIFIER (const Wide::ParsedFile::Identifier*& v)
{
return symbol_type (token::IDENTIFIER, v);
}
symbol_type takes a variant as it's second argument in this specific constructor, and v is being implicitly converted.
However, MSVC will try to use the rvalue reference constructor instead of using the other constructor, resulting in a compilation error when it attempts to new a reference. Why is that, and how can I make it stop?
You generally should not overload a templated T&& function. You should instead have the single function which forwards:
template <typename T>
inline
variant (T&& t)
{
typedef typename std::remove_reference<T>::type Tr;
YYASSERT (sizeof (Tr) <= S);
new (buffer.raw) Tr(std::forward<T>(t));
}
This has the functionality of your two overloads, while avoiding the problem of picking the wrong one.
I believe (not positive) that these are the two variants in your overload set:
varaint<const Wide::ParsedFile::Identifier*>(const Wide::ParsedFile::Identifier*const&)
varaint<const Wide::ParsedFile::Identifier*&>(const Wide::ParsedFile::Identifier*&)
And the second one wins because it is more specialized than the first (I'm making an educated guess, I'm not 100% positive).
The second template would be a better match, because the const specifiers are in different places in your function and in the first constructor.
In the first overload you will have T being deduced as
const Wide::ParsedFile::Identifier*
And then creating a const reference to that type. That adds an extra const.

Resources