Recursive Typedef in C++ - c++

I want to write a typedefinition in c++, but do not know if something I want to implement is legal. Let's say I want to do a typedef of a vector of boost variant types, which point to an int, or another vector of the same type. So, would this be legal and would the compiler complain?
typedef std::vector<boost::variant<int *, boost::variant<int *, IntBranch*>> IntBranch;

You can use boost::make_recursive_variant for that purpose:
#include <boost/variant.hpp>
typedef boost::make_recursive_variant<
int*,
std::vector< boost::recursive_variant_ >
>::type IntBranch;
And this is how you would use it:
#include <vector>
int main()
{
typedef boost::make_recursive_variant<
int*,
std::vector< boost::recursive_variant_ >
>::type IntBranch;
int x = 42;
IntBranch ib = &x;
std::vector<IntBranch> v;
v.push_back(ib);
IntBranch ib2 = v;
// ...
}
And here is a live example.

Related

map with key which is combination of multiple values in c++

I want a map in c++, in which its key is combination of multiple values. I can use both stl and boost also.
Key values can be string/integers something like below
typedef value_type int;
typedef key(string, template(string,int), template(string,int)) key_type;
typedef map(key_type, value_type) map_type;
map_type map_variable;
map_variable.insert(key_type("keyStrning1", 1, "keyString2"), 4);
map_variable.insert(key_type("keyStrning3", 1, "keyString2"), 5);
Now this map will contain two entries and i shall be able to find it like below:
map_variable.find(key_type("keyStrning3", 1, "keyString2")).
I can use nested maps , but i want to know is there any convenient solution for this using either boost or c++ stl.
You can use boost::variant (or std::variant when C++17 will be ready).
#include <tuple>
#include <map>
#include <utility>
#include <boost/variant/variant.hpp>
typedef int ValueType;
typedef boost::variant<std::string, int> StrOrInt;
typedef std::tuple<std::string, StrOrInt, StrOrInt> KeyType;
typedef std::map<KeyType, ValueType> MapType;
int main(int argc, char *argv[]) {
MapType amap;
amap.insert(std::make_pair(
std::make_tuple("string1", "string2", 3), <--- key
4)); // <--- value
auto finder = amap.find(std::make_tuple("string1", "string2", 3));
std::cout << finder->second << '\n'; // <--- prints 4
return 0;
}

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 > ));

Convert boost::bimap to std::map

The obvious way to convert a bimap to std::map, doesnt seem to work. Is below the correct/good way to convert? Is there a better/shorter way?
typedef boost::bimap<int, std::string> MapType;
MapType _bimap;
//Fill _bimap
MapType::left_map& lmap = _bimap.left;
//std::map<int, std::string> bmap(lmap.begin(), lmap.end()); //THIS DOESNT WORK
std::map<int, std::string> bmap;
BOOST_FOREACH(MapType::left_const_reference entry, lmap)
{
bmap[entry.first] = entry.second;
}
The values from a bimap cannot be directly assigned to thos of a map because there is a problem of type (ignoring the more obvious problem of const-ness of the value):
When a bimap left view iterator is dereferenced the return type is signature-compatible with a std::pair< const A, const B >
(source)
And :
A type is signature-compatible with other type if it has the same signature for functions and metadata. Preconditions, postconditions and the order of operations need not be the same.
That means that there is no guarantee that your bimap value_type is assignable or copyable to a map value_type. In fact it is not:
typedef boost::bimap<int, std::string> BiMapType;
typedef std::map<int, std::string> MapType;
BiMapType bimap;
BiMapType::left_value_type t1 = *(bimap.left.begin()); // Mandatory for compilation on my version at least
MapType::value_type t2(t1);
That will fail horribly (same kind of thing if you try t2 = t1;)
So either you find a way to convert your value_types either you keep with a for_each/transform/copy ... idiom.
There is a neat solution signaled here in comment by #CharlesPehlivanian (that he will maybe provide as an answer also), that is to use boost::trasnform_iterator.
For that you have to provide a transformer functor (it does not work with a raw lambda, you have to use a struct with operator() and result_type or a std::function) that will convert the input iterator value to the output one:
typedef std::function<MapType::value_type (const BiMapType::left_value_type&)>
Transformer;
Transformer transformer_func = [](const BiMapType::left_value_type& elem)
{
return std::make_pair(elem.first, elem.second);
};
Then you just have to wrap begin and end iterator with boost::make_transform_iterator:
auto begin = boost::make_transform_iterator(bimap.left.begin(), transformer_func);
auto end = boost::make_transform_iterator(bimap.left.end(), transformer_func);
Here is the whole code:
#include <boost/bimap.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <map>
int main(int argc, char const *argv[])
{
typedef boost::bimap<int, std::string> BiMapType;
typedef std::map<int, std::string> MapType;
typedef std::function<MapType::value_type (const BiMapType::left_value_type&)>
Transformer;
BiMapType bimap;
Transformer transformer_func = [](const BiMapType::left_value_type& elem)
{
return std::make_pair(elem.first, elem.second);
};
auto begin = boost::make_transform_iterator(bimap.left.begin(), transformer_func);
auto end = boost::make_transform_iterator(bimap.left.end(), transformer_func);
MapType map(begin, end);
return 0;
}
http://coliru.stacked-crooked.com/a/8fae0d47ca4b72a1

Get point-to type of boost shared_ptr

In my project, I use boost::shared_ptr, in one header file, I wrote:
typedef boost::shared_ptr<boost::lockfree::spsc_queue<PacketsInput, boost::lockfree::capacity<4096> > > queue_ptr;
In another source file, I use it:
std::vector<queue_ptr> v;
for (...)
v.push_back(boost::make_shared(/* #1 */));
In #1, I want to write queue_ptr's point to type, rather
boost::lockfree::spsc_queue<PacketsInput, boost::lockfree::capacity<4096> >
how long it is!
But there is no typedef in boost::shared_ptr, the only one I found is a typedef: typedef typename boost::detail::sp_element< T >::type element_type; But I don't know how to use it.
Any help? Tanks a lot!
Documentation says there's a member typedef called element_type:
This example program runs fine (assertion passes):
#include <boost/shared_ptr.hpp>
#include <boost/type_traits.hpp>
#include <cassert>
int main()
{
bool b = boost::is_same<boost::shared_ptr<int>::element_type, int>::value;
assert(b);
}
Given the typedef you've already declared, you can use it like this:
typedef queue_ptr::element_type elem_type;
v.push_back( boost::make_shared<elem_type>( /* args for ctor */ ) );
You could use two typedefs
typedef boost::lockfree::spsc_queue<PacketsInput, boost::lockfree::capacity<4096> > my_queue;
typedef boost::shared_ptr<my_queue> my_queue_ptr;
And then you can use my_queue in make_shared.

__gnu_cxx hash map with keys of type std::pair<std::string, unsigned int>?

Since std::pair<std::string, unsigned int> is not defined for __gnu_cxx hash map, how do I create a __gnu_cxx hash map with keys of type std::pair<std::string, unsigned int> and values of type std::pair<int, CBTNODE>? (CBTNODE is typedef as typedef int CBTNODE)
If it's possible, I would really want to substitute std::pair<std::string, unsigned int> with a typedef-ed INDEX (typedef std::pair<std::string, unsigned int> INDEX)
Any help will be much appreciated!
Z.Zen
This seems to compile and print the right answer (1):
#include <hash_map>
#include <utility>
#include <string>
#include <iostream>
typedef int CBTNODE;
typedef std::pair<std::string, unsigned int> INDEX;
typedef std::pair<int, CBTNODE> Element;
struct pairhash{
size_t operator()(const INDEX &p) const {
return
__gnu_cxx::hash<const char*>()(p.first.c_str()) ^
__gnu_cxx::hash<unsigned int>()(p.second);
}
};
int main() {
__gnu_cxx::hash_map<INDEX, Element, pairhash> x;
INDEX foo("hi", 0);
Element bar(1, 2);
x[foo] = bar;
std::cout << x[foo].first << "\n";
}
Which was a bit tedious. The issue is that __gnu_cxx::hash doesn't provide a specialization for pair, or for that matter for string either. I believe it follows the SGI API here: http://www.sgi.com/tech/stl/hash.html. So pairhash (or something like it) is needed to provide the missing hash function.
I don't blame you for not spotting that, since the compiler error that this caused was a bit, um, non-obvious. And long.
If you can, you're probably better off using boost::unordered_map. SGI's hash_map is an old API, never adopted into the standard, due to be replaced in C++0x, etc, etc.