How do I merge two mpl maps producing a new map? - c++

However I tweek the following code, there seems to be a point I am missing. It will not compile. I have two maps int -> int. I want to produce a third int -> int map containing all the key-value pairs from the two originals. (VS2013) Anyone?
#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/has_key.hpp>
typedef boost::mpl::map <
boost::mpl::pair < boost::mpl::int_<7>, boost::mpl::int_<59> >
>::type Original1;
typedef boost::mpl::map <
boost::mpl::pair < boost::mpl::int_<11>, boost::mpl::int_<61> >
>::type Original2;
typedef boost::mpl::copy <
Original1,
boost::mpl::back_inserter < Original2 >
>::type Merged;
BOOST_MPL_ASSERT((boost::mpl::has_key<Merged, 7>));
int _tmain(int argc, _TCHAR* argv[])
{
const int i = boost::mpl::at<Merged, boost::mpl::int_<7> >::type::value;
return 0;
}

There are two problems with your code. The simple one is here:
BOOST_MPL_ASSERT((boost::mpl::has_key<Merged, 7>));
Keys are types, 7 is not a type. You want to check for the key mpl::int_<7>.
The second is here:
typedef boost::mpl::copy <
Original1,
boost::mpl::back_inserter < Original2 > // <==
>::type Merged;
mpl::back_inserter is the metaprogramming equivalent of std::back_inserter, which creates an OutputIterator which outputs via push_back(). Similarly, back_inserter requires a "Back Extensible Sequence" because it uses mpl::push_back. mpl::map isn't a Back Extensible Sequence. If you look at its reference, there's no push_back, only insert. So you need to do that:
using Merged =
mpl::copy<
Original1,
mpl::inserter<Original2, mpl::insert<mpl::_1, mpl::_2>> // <==
>::type;
I don't quite understand what mpl::quote is doing, but it seems broken (er, actually, mpl::insert takes 3 arguments and mpl::quote3 doesn't allow for defaulting the last arguments). If you write:
template <template <class... > class F>
struct quote {
template <class... Args>
struct apply {
using type = typename F<Args...>::type;
};
};
then you could have just written:
mpl::inserter<Original2, quote<mpl::insert>>

Related

How to find the type of a pair from iterator?

I am newbee here as well as in template programming.
I have a dictionary (means, it could be either std::map or std::vector<std::pair<type1, type2>> or std::set<std::pair<, >> ...)
I wanted to write an algorithm, which act like standard library algorithms
using the iterators of the passed container.
Following is the idea.
#include <iostream>
#include <algorithm>
#include <type_traits>
#include <vector>
#include <array>
#include <map>
#include <set>
#include <iterator>
// two different types
enum EnumA { one, two, three, four, five, six};
enum EnumB { one, three, four, six};
// TypeA TypeB
using map = std::map<EnumA, EnumB>;
// or std::vector<std::pair<EnumA, EnumB>>
// or std::set<std::pair<EnumA, EnumB>>
// or std::array<std::pair<EnumA, EnumB>, 3>
const map itemMap{ // the map
{EnumA::one, EnumB::one},
{EnumA::three, EnumB::three},
{EnumA::six, EnumB::six},
};
template<typename Iterator, typename B>
/* type of KEY(first) of the map/container from the iterator???*/ AfromB(Iterator begin, Iterator end, B bObj)
{
// static_assert(begin != end); // container should not be empty!
using Type = typename std::iterator_traits<Iterator>::value_type;
using AType = decltype( /* how to find the type of KEY(first) of the map/container? */);
using BType = decltype(/* how to find the type of VALUE(second) of the map/container? */);
auto iter = std::find_if(begin, end, [bObj](const Type& entry) { return entry.second == bObj;});
return iter != end ? iter->first: begin->first; // if not found return the first element match
}
// will do BfromA(Iterator begin, Iterator end, B bObj) similarly afterwards
int main()
{
EnumA aEnum = AfromB(itemMap.cbegin(), itemMap.cend(), EnumB::six); // I can use it like
}
There you can see in the code, I do not know how to find the type of
key/ first and value/second of the pair in the dictionary. After googling,
I found I can find the type of key-value pair by
using Type = typename std::iterator_traits<Iterator>::value_type;
but not for the individuals of that pair. Is it possible to find?
Im using C++11.
Sorry for the bad English. Thanks for the help.
You already have the maps value type:
using Type = typename std::iterator_traits<Iterator>::value_type;
A maps value type is a std::pair<first_type,second_type> and to get a pairs first and second type you can use its first_type and second_type:
using key_type = typename Type::first_type;
using mapped_type = typename Type::second_type;
To use the key_type as return type I'd probably use a small helper:
template <typename Iterator>
struct KeyAndMappedType {
using value_type = typename std::iterator_traits<Iterator>::value_type;
using const_key_type = typename value_type::first_type;
using key_type = typename std::remove_const<const_key_type>::type;
using mapped_type = typename value_type::second_type;
};
and then
template <typename Iterator, typename B>
typename KeyAndMappedType<Iterator>::key_type AfromB(Iterator begin, Iterator end, B bObj) {
...
}
Note that a maps key_type is always const. As sometimes you need that type also as non-const, I decided that my KeyAndMapType should provide both (maybe naming should have been reversed, ie key_type as const and a non_const_key_type, but I'll leave it up to you to decide on the details).

Why bool is not regarded as boost::true_type in C++?

The following codes come from an example code to illustrate how to use boost::type_traits. It will use two methods to swap two variables. It is easy to understand that when the two variables are integer (int) their type traits correspond to true_type. However, when two variables are bool type they are not regarded as true_type any more. Why would it happen? Thanks.
#include <iostream>
#include <typeinfo>
#include <algorithm>
#include <iterator>
#include <vector>
#include <memory>
#include <boost/test/included/prg_exec_monitor.hpp>
#include <boost/type_traits.hpp>
using std::cout;
using std::endl;
using std::cin;
namespace opt{
//
// iter_swap:
// tests whether iterator is a proxying iterator or not, and
// uses optimal form accordingly:
//
namespace detail{
template <typename I>
static void do_swap(I one, I two, const boost::false_type&)
{
typedef typename std::iterator_traits<I>::value_type v_t;
v_t v = *one;
*one = *two;
*two = v;
}
template <typename I>
static void do_swap(I one, I two, const boost::true_type&)
{
using std::swap;
swap(*one, *two);
}
}
template <typename I1, typename I2>
inline void iter_swap(I1 one, I2 two)
{
//
// See is both arguments are non-proxying iterators,
// and if both iterator the same type:
//
typedef typename std::iterator_traits<I1>::reference r1_t;
typedef typename std::iterator_traits<I2>::reference r2_t;
typedef boost::integral_constant<bool,
::boost::is_reference<r1_t>::value
&& ::boost::is_reference<r2_t>::value
&& ::boost::is_same<r1_t, r2_t>::value> truth_type;
detail::do_swap(one, two, truth_type());
}
}; // namespace opt
int cpp_main(int argc, char* argv[])
{
//
// testing iter_swap
// really just a check that it does in fact compile...
std::vector<int> v1;
v1.push_back(0);
v1.push_back(1);
std::vector<bool> v2;
v2.push_back(0);
v2.push_back(1);
opt::iter_swap(v1.begin(), v1.begin()+1);
opt::iter_swap(v2.begin(), v2.begin()+1);
return 0;
}
You've got the answer there in your code (as a comment):
See is both arguments are non-proxying iterators
vector<bool> has proxy iterators, because you can't refer directly to a bit.
If vector<bool> stored its' elements as individual booleans (taking 1-4 bytes/entry, depending on the system), the iterators could be non-proxying. But instead, vector<bool> stores 8 entries/byte and uses proxy iterators.

Transforming mpl vector with own function

I want to multiply each element in an mpl::vector by an int.
First, a metafunction to multiply an int_ with an int.
template <int i>
struct multiply_scalar
{
template<typename T> struct apply
{
typedef int_<(T::value * i)> type;
};
};
Here are the calls I want to make.
typedef vector<int_<3>, int_<4> > my_vec;
typedef typename transform< my_vec, multiply_scalar<2> >::type my_vec_2;
typedef vector<int_<6>, int_<8> > my_vec_3;
BOOST_MPL_ASSERT(( boost::is_same< my_vec_2, my_vec_3 > )); //Fails
//type of my_vec2 is: boost::mpl::v_item<mpl_::int_<8>, boost::mpl::v_item<mpl_::int_<6>, boost::mpl::vector0<mpl_::na>, 0>, 0>
Why isn't the resulting vector simply a vector<int_<6>, int_<8>>? Am I holding it wrong? Probably the metafunction or the transform is not applied in the right way.
Mainly because of some implementation issues in C++03, the writers of the MPL
had to use non-obvious techniques for representing sequences, one of which is
the usage of types like
boost::mpl::vector0<>
boost::mpl::vector1<T>
boost::mpl::vector2<T, U>
... etc
Instead of simply writing
boost::mpl::vector<>
boost::mpl::vector<T>
boost::mpl::vector<T, U>
as one would do with variadic templates in C++11 and beyond. Another technique
is to create some kind of reverse linked list when you insert stuff in a vector,
which is what you're looking at in your example:
boost::mpl::v_item<mpl_::int_<8>, // 2nd element
boost::mpl::v_item<mpl_::int_<6>, // 1st element
boost::mpl::vector0<mpl_::na>, 0>, 0> // empty list
Because of this, the documentation
for boost::mpl::transform does not specify exactly what is the type of boost::mpl::transform<s,op,in>::type.
Actually, it only guarantees that it's a type equivalent to
typedef lambda<op>::type f;
typedef lambda<in::operation>::type in_op;
typedef fold<
s
, in::state
, bind< in_op, _1, bind<f, _2> >
>::type r; // <-- the return type is equivalent to this r
This probably does not help you unless you already know the MPL well enough that
you don't ask questions on SO about it ;-), so basically it means that it returns
a new type that's like a boost::mpl::vector, except for its actual type which may
be anything like I showed above. In particular, this type is guaranteed to be a model
of the Forward Sequence concept.
When you use boost::is_same<T, U>, you're actually asking whether T and U
are precisely the same types. You should now see clearly why this is not what
you actually want. Instead, you want to do some kind of deep comparison of those
two sequences, which both represent vectors. To check whether two Forward
Sequences are equal, you must use the boost::mpl::equal
algorithm instead. The following will work:
#include <boost/mpl/assert.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>
using namespace boost::mpl;
template <int i>
struct multiply_scalar
{
template<typename T> struct apply
{
typedef int_<(T::value * i)> type;
};
};
typedef vector<int_<3>, int_<4> > my_vec;
typedef transform< my_vec, multiply_scalar<2> >::type my_vec_2;
typedef vector<int_<6>, int_<8> > my_vec_3;
BOOST_MPL_ASSERT(( boost::mpl::equal< my_vec_2, my_vec_3 > ));

C++ Compiler Error (trying to create a static vector of vectors)

I'm trying to create a static vector-of-vectors and I'm finding that the following code compiles and runs under gcc-4.1.2 but under gcc-4.5.1 it fails to compile with the message
assign.cxx:19:48: error: no matching function for call to ‘to(boost::assign_detail::generic_list<std::basic_string<char> >&)’
Can anyone explain why this happens? If you have any other suggestions about how to do what I'm trying to do then I'd be happy with that instead :).
#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>
template <template <typename> class containerType, typename elemType>
containerType<elemType> to( boost::assign_detail::generic_list<elemType> list ) {
containerType<elemType> tempContainer = list;
return tempContainer;
}
static const std::vector<std::vector<std::string> > names = boost::assign::list_of
(to<std::vector>(boost::assign::list_of<std::string>("A")("B")("C") ))
(to<std::vector>(boost::assign::list_of<std::string>("D")("E")("F") ));
int main() {
for( std::vector< std::vector<std::string> >::const_iterator itVec = names.begin(); itVec != names.end(); ++itVec ) {
for( std::vector<std::string>::const_iterator itStr = itVec->begin(); itStr != itVec->end(); ++itStr ) {
std::cout << "Value is " << *itStr << std::endl;
}
}
return 0;
}
The problem stems from the fact that in your definition of to<>(), containerType is declared to have only one template parameter, when in fact std::vector<> has two template parameters.
The fact that this compiles in GCC 4.1.2 only indicates a bug in GCC 4.1.2 -- the code is still inherently incorrect.
Unfortunately, I can't think of a good workaround offhand. The following compiles but restricts you to containers with only two template arguments (wherein the second is the allocator), which may not be what you ultimately want:
#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>
template<
template<typename, typename> class containerType,
typename allocatorType,
typename elemType
>
containerType<elemType, allocatorType >
to(boost::assign_detail::generic_list<elemType> const& list)
{
return list; // no need to explicitly construct a containerType instance
}
template<template<typename, typename> class containerType, typename elemType>
containerType<elemType, std::allocator<elemType> >
to(boost::assign_detail::generic_list<elemType> const& list)
{
return to<containerType, std::allocator<elemType> >(list);
}
static std::vector<std::vector<std::string> > names = boost::assign::list_of
(to<std::vector>(boost::assign::list_of<std::string>("A")("B")("C")))
(to<std::vector>(boost::assign::list_of<std::string>("D")("E")("F")));
int main()
{
typedef std::vector<std::vector<std::string> >::const_iterator outer_iter_t;
typedef std::vector<std::string>::const_iterator inner_iter_t;
for (outer_iter_t itVec = names.begin(); itVec != names.end(); ++itVec)
for (inner_iter_t itStr = itVec->begin(); itStr != itVec->end(); ++itStr)
std::cout << "Value is " << *itStr << '\n';
}
EDIT (in response to dribeas' comment): Updated to allow the caller to override the default allocator.
After going around the problem a couple of things, I believe that the simplest solution is not using a template template argument, but rather a type template argument:
template <typename containerType, typename elemType>
containerType to( boost::assign_detail::generic_list<elemType> list ) {
containerType tempContainer = list;
return tempContainer;
}
static const std::vector<std::vector<std::string> > names = boost::assign::list_of
(to<std::vector<std::string> >(boost::assign::list_of<std::string>("A")("B")("C") ))
(to<std::vector<std::string> >(boost::assign::list_of<std::string>("D")("E")("F") ));
It might require a bit more typing in the calling side, but it will take care of the extra template arguments that you are not declaring in your template template argument.
Your call to the function to<std::vector>( ... ) only contains one template parameter, whereas you function declaration contains two. I would try: to<std::vector, std::string>( ... )

How to insert a pair of std::pair inside another std::pair?

I'm declaring a map of string to a pair of pairs as follow:
std::map<std::wstring,
std::pair<std::pair<long, long>,
std::pair<long, long>>> reference;
And I initialize it as:
reference.insert(L"First",
std::pair<std::pair<long, long>,
std::pair<long, long>>(std::pair<long, long>(-1, -1),
std::pair<long, long>(0, 0)));
However, Visual C++ gives me the error "C2664, No constructor could take the source type, or constructor overload resolution was ambiguous".
I'm new to using templates and STL and I can't tell what I'm doing wrong.
The >>> can not be parsed correctly (unless you have a C++0x compiler).
Change to > > >
This:
reference.insert("First",
Should be:
reference.insert(L"First",
^^^
Also there is a utility function to make the construction of pairs easier:
std::pair<std::pair<long, long>, std::pair<long, long>>(std::pair<long, long>(-1, -1), std::pair<long, long>(0, 0))
Can be:
std::make_pair(std::make_pair(-1L,-1L),std::make_pair(0L,0L))
Try this:
reference[L"First"]
= std::make_pair(std::make_pair(-1L,-1L),std::make_pair(0L,0L));
C++ gets confused by the consecutive ">" when you close the template as it interprets that as the shift operator.
Add spaces between the closing templates, change >>> to > > >
map::insert itself takes a single std::pair argument, rather than two arguments. You can tidy up the code by using std::make_pair (which infers the template arguments from the function arguments), to get something like:
reference.insert(std::make_pair("First",
std::make_pair(std::make_pair(-1L,-1L),
std::make_pair(0L,0L))));
You could simplify your code by creating a helper function to create pairs of pairs, analog to the std::make_pair helper function that is available in the standard library. Also using the maps operator[] for insertion results in easier to read code:
template<typename T, typename U, typename V, typename W>
std::pair< std::pair<T,U>, std::pair<V,W> > make_pair_pair(T t, U u, V v, W w) {
// using std::make_pair instead of the constructor for better readability
return std::make_pair(std::make_pair(t, u), std::make_pair(v, w));
}
reference[L"First"] = make_pair_pair(1,2,3,4);
It helps to use typedefs when debugging this sort of thing.
// test1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <map>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
typedef std::pair<long, long> ElementType;
typedef std::pair<ElementType, ElementType> ValueType;
typedef std::wstring KeyType;
std::map<KeyType, ValueType> reference;
KeyType key = L"First";
reference[key] = ValueType(ElementType(-1, -1), ElementType(0, 0));
return 0;
}