how to call a templetized vector of records - c++

I'm having a problem getting the syntax right so if someone can help,please?
I have a timing function which take a function and its arguments as a parameters, but I'm not sure how should the call look like.
#include <iostream>
#include <iterator>
#include <random>
#include <vector>
#include<list>
#include<deque>
#include <algorithm>
#include <chrono>
#include <functional>
#include <sstream>
using namespace std;
using namespace std::chrono;
int global_SortType = 1;
template<class F, class A, typename T>
void times(F func, A arg, int n, T typeval) // call func(arg,n)
{
auto t1 = system_clock::now();
func(arg, n, typeval);
auto t2 = system_clock::now();
auto dms = duration_cast<milliseconds>(t2-t1);
cout << "f(x) took " << dms.count() << " milliseconds\n";
}
template<class T>
bool Greater(const T& v1, const T& v2)
{
return false;
}
bool Greater(const int& v1, const int& v2)
{
return v1 > v2;
}
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
}
template <class T>
struct GreaterThan: public std::binary_function<T, T, bool > {
bool operator () ( const T &ival, const T &newval ) const {
return Greater(ival, newval);
}
};
string random_gen(string& s)
{
string Result; // string which will contain the result
ostringstream convert; // stream used for the conversion
convert << rand();
return convert.str();
}
int random_gen(int& i){
default_random_engine re { std::random_device()() };
uniform_int_distribution<int> dist;
auto r= bind(dist,re);
int x =r();
return x;
}
template<class T>
void print(T& val)
{
}
void print(int& val)
{
cout << val << " ";
}
void print(string& val)
{
cout << val.c_str() << " ";
}
struct Record
{
int v;
string s;
Record(){}
Record(int iv, string ss): v(iv), s(ss)
{
}
};
Record random_gen(Record& r)
{
string stemp;
int i = 0;
return Record(random_gen(i), random_gen(stemp));
}
void print(Record& r)
{
cout<<"int="<<r.v<<" string=";
print(r.s);
}
bool Greater(const Record& r1, const Record& r2)
{
return global_SortType == 1 ? Greater(r1.v, r2.v) : Greater(r1.s, r2.s);
}
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::const_iterator it;
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::const_iterator it=seq.begin();
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
int main()
{
int n=1000;
vector<int> v;
times(build_cont<std::vector<int>, int>, v, n, 0); // works
vector<string> sv;
string stemp = "";
times(build_cont<std::vector<string>, string>, sv, n, stemp); // works
global_SortType = 1;
vector<Record> rv;
Record rtemp(0, "sfds");
global_SortType = 2;
vector<Record> rsv;
Record rstemp(0, "sfds");
//This one desn't work and I'm not sure of the right syntax
times(build_cont<std::vector<Record>,Record>, sv, n, stemp);
return 0;
}
I'm getting this error
Non-const lvalue reference to type 'vector>' cannot bind to a value of unrelated type 'vector, allocator>>'
and it points to line
func(arg, n, typeval);

Inside this function:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
You are using const_iterators rather than iterators to perform insertions and removals. You should change the definition of that function as follows:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::iterator it;
// ^^^^^^^^
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::iterator it=seq.begin();
// ^^^^^^^^
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
Also, you forgot to #include the <cstring> standard header, which contains the definition for the strcmp() function. You are using that function inside your Greater() function:
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
// ^^^^^^
// You need to #include <cstring> before calling this function
}
Moreover, you're invoking function times() with the wrong arguments (sv and stemp):
//This one desn't work and I'm not sure of the right sytax
times(build_cont<std::vector<Record>,Record>, rsv, n, rstemp);
// ^^^ ^^^^^^

Related

Problems with implementing 2D array template in C++

I tried to create a template for a generic 2D array, which would allow me to create arrays of different data types and fill them with random values. My current code seemingly creates three objects, but fills them with the same random values, and the double type massive does not even have double values. I think the problem is somewhere in the constructor and with the pointers, but I am not sure how to fix this.
My class:
template <typename T>
class MATRIX
{
private:
T** M;
int m = 8;
int n = 12;
public:
MATRIX(T matr[8][12]);
void fill();
};
Constructor:
template <typename T>
MATRIX<T>::MATRIX(T matr[8][12]){
M = (T**) new T*[m];
for (int i = 0; i < m; i++)
M[i] = (T*)new T[n];
}
Method:
template <typename T>
void MATRIX<T>::fill(){
T randomNumber;
srand((unsigned) time(0));
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
randomNumber = (rand() % (122 + 1 - 65)) + 65;
M[i][j] = randomNumber;} } }
Main:
int main() {
int intMatr[8][12];
MATRIX<int>a(intMatr);
a.fill();
double doubleMatr[8][12];
MATRIX<double>b(doubleMatr);
b.fill();
char charMatr[8][12];
MATRIX<char>c(charMatr);
c.fill();
return 0; }
Not really a direct answer to your question, howeverr try not to use new/delete if you don't have to as is shown in this example (note the array2d_t class is something I wrote earlier and reused for this example so it can do a bit more then needed)
I also show how to use c++'s random generators to create characters for your matrix.
#pragma once
#include <vector>
#include <iostream>
#include <random>
#include <utility>
#include <string>
#include <stdexcept>
//---------------------------------------------------------------------------------------------------------------------
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
struct array2d_t
{
constexpr array2d_t() :
m_values{}
{
}
constexpr explicit array2d_t(const type_t(&values)[rows_v][cols_v])
{
// constexpr compatible initialization
for (auto row = 0; row < rows_v; ++row)
{
for (auto col = 0; col < cols_v; ++col)
{
m_values[row][col] = values[row][col];
}
}
}
~array2d_t() = default;
// return a row
constexpr auto operator[](const std::size_t row)
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return row_t(&m_values[row][0]);
}
// return a const row
constexpr auto operator[](const std::size_t row) const
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return const_row_t(&m_values[row][0]);
}
// return iterator to the first row (so array can be used in range based for loop)
constexpr auto begin()
{
return std::begin(m_values);
}
// return iterator to the last row (so array can be used in range based for loop)
constexpr auto end()
{
return std::end(m_values);
}
constexpr std::size_t rows() const
{
return rows_v;
}
constexpr std::size_t columns() const
{
return cols_v;
}
private:
//-----------------------------------------------------------------------------------------------------------------
/// row helper
struct row_t
{
constexpr row_t(type_t* row) :
m_row{ row }
{
}
constexpr type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
type_t* m_row;
};
//-----------------------------------------------------------------------------------------------------------------
// row helper for const
struct const_row_t
{
constexpr const_row_t(const type_t* row) :
m_row{ row }
{
}
constexpr const type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
const type_t* m_row;
};
type_t m_values[rows_v][cols_v];
};
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
std::ostream& operator<<(std::ostream& os, array2d_t<type_t,rows_v,cols_v>& arr)
{
for (const auto& row : arr)
{
bool comma = false;
for (const auto& value : row)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
std::cout << "\n";
return os;
}
//---------------------------------------------------------------------------------------------------------------------
class MATRIX :
public array2d_t<char, 8, 12>
{
public:
void fill()
{
// initialize a vector of valid character for random to pick from
// static ensures this is only done on first call to function
static std::vector<char> valid_chars = []
{
std::vector<char> chars;
chars.reserve(52);
for (char c = 'A'; c < 'Z'; ++c) chars.push_back(c);
for (char c = 'a'; c < 'z'; ++c) chars.push_back(c);
return chars;
}();
// this is how to setup random number generation in C++
static std::random_device rd{};
static std::default_random_engine random{ rd() };
static std::uniform_int_distribution<std::size_t> distribution(0, valid_chars.size() - 1);
for (auto& row : *this)
{
for (auto& value : row)
{
value = valid_chars[distribution(random)];
}
}
}
};
//---------------------------------------------------------------------------------------------------------------------
int main()
{
MATRIX m;
m.fill();
std::cout << m;
return 0;
}

I am having problems making a function that returns one of few templated parameters cpp

i am trying to build a dictionary in cpp that takes 2 template argumemts (), and i have a "get" function that should return the value only.
this is the class header:
#include <iostream>
#include <vector>
using namespace std;
template <class K, class V>
class Dict {
protected:
vector<K> keys;
vector<V> values;
K Key;
V Value;
public:
Dict();
void set(K Key, V Value);
V get(string key);
};
this is the class cpp:
#include "Dict.h"
template <class K, class V>
Dict<K,V>::Dict() {};
template <typename K, typename V>
V Dict<K,V>::get(K key) {
V lol;
bool found = false;
for(int i = 0; i < this->keys.size(); i++){
if(this->keys[i] == key){
return *this->values[i];
}
}
cout << "This Key does not exists";
return lol;
}
template <typename K, typename V>
void Dict<K,V>::set(K Key, V Value) {
keys.push_back(Key);
values.push_back(Value);
}
template class Dict<string, int>;
this is the main:
#include "Dict.h"
int main() {
Dict<string, int> d;
d.set("yoav", 34);
d.set("hey", 8);
int num = d.get("hey");
cout << num;
return 0;
}
and the compiler throws this:
error: prototype for ‘V Dict<K, V>::get(K)’ does not match any in class ‘Dict<K, V>’
V Dict<K,V>::get(K key) {
^
Besides the fact, that you should put the template-implementation not in the cpp-file, but into the header, there is an other error.
return *this->values[i];
should be either
return this->values[i];
or
return (*this).values[i];
And the working(=compiling) code
#include <iostream>
#include <vector>
using namespace std;
template <class K, class V>
class Dict {
protected:
vector<K> keys;
vector<V> values;
K Key;
V Value;
public:
Dict() {
}
void set(K Key, V Value) {
keys.push_back(Key);
values.push_back(Value);
}
V get(string key) {
V lol;
bool found = false;
for(int i = 0; i < this->keys.size(); i++){
if(this->keys[i] == key){
return this->values[i];
}
}
cout << "This Key does not exists";
return lol;
}
};
int main() {
Dict<string, int> d;
d.set("yoav", 34);
d.set("hey", 8);
int num = d.get("hey");
cout << num;
return 0;
}

How to generate nested loops at compile time

I have an integer N which I know at compile time. I also have an std::array holding integers describing the shape of an N-dimensional array. I want to generate nested loops, as described bellow, at compile time, using metaprogramming techniques.
constexpr int N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
auto f = [/* accept object which uses coords */] (auto... coords) {
// do sth with coords
};
// This is what I want to generate.
for(int i = 0; i < shape[0]; i++) {
for(int j = 0; j < shape[1]; j++) {
for(int k = 0; k < shape[2]; k++) {
for(int l = 0; l < shape[3]; l++) {
f(i,j,k,l) // object is modified via the lambda function.
}
}
}
}
Note the parameter N is known at compile time but might change unpredictably between compilations, hence I can't hard code the loops as above. Ideally the loop generation mechanism will provide an interface which accepts the lambda function, generates the loops and calls the function producing the equivalent code as above. I am aware that one can write an equivalent loop at runtime with a single while loop and an array of indices, and there are answers to this question already. I am, however, not interested in this solution. I am also not interested in solutions involving preprocessor magic.
Something like this (NOTE: I take the "shape" as a variadic template argument set..)
#include <iostream>
template <int I, int ...N>
struct Looper{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
Looper<N...>()(f, x..., i);
}
}
};
template <int I>
struct Looper<I>{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
f(x..., i);
}
}
};
int main()
{
int v = 0;
auto f = [&](int i, int j, int k, int l) {
v += i + j + k + l;
};
Looper<1, 3, 5, 2>()(f);
auto g = [&](int i) {
v += i;
};
Looper<5>()(g);
std::cout << v << std::endl;
}
Assuming you don't want total loop unrolling, just generation of i, j, k etc. argument tuples for f:
#include <stdio.h>
#include <utility> // std::integer_sequence
template< int dim >
constexpr auto item_size_at()
-> int
{ return ::shape[dim + 1]*item_size_at<dim + 1>(); }
template<> constexpr auto item_size_at<::N-1>() -> int { return 1; }
template< size_t... dim >
void call_f( int i, std::index_sequence<dim...> )
{
f( (i/item_size_at<dim>() % ::shape[dim])... );
}
auto main()
-> int
{
int const n_items = ::shape[0]*item_size_at<0>();
for( int i = 0; i < n_items; ++i )
{
call_f( i, std::make_index_sequence<::N>() );
}
}
I suppose this is exactly what you asked for:
#include <array>
#include <iostream>
constexpr int N{4};
constexpr std::array<int, N> shape {{1,3,5,2}};
// Diagnositcs
template<typename V, typename ...Vals>
struct TPrintf {
constexpr static void call(V v, Vals ...vals) {
std::cout << v << " ";
TPrintf<Vals...>::call(vals...);
}
};
template<typename V>
struct TPrintf<V> {
constexpr static void call(V v) {
std::cout << v << std::endl;
}
};
template<typename ...Vals>
constexpr void t_printf(Vals ...vals) {
TPrintf<Vals...>::call(vals...);
}
// Unroll
template<int CtIdx, typename F>
struct NestedLoops {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[CtIdx]; ++i) {
NestedLoops<CtIdx + 1, F>::call(f, idx..., i);
}
}
};
template<typename F>
struct NestedLoops<N-1, F> {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[N-1]; ++i) {
f(idx..., i);
}
}
};
template<typename F>
void nested_loops(const F& f) {
NestedLoops<0, F>::call(f);
}
int main()
{
auto lf = [](int i, int j, int k, int l) {
t_printf(i,j,k,l);
};
nested_loops(lf);
return 0;
}
Another variant of the same thing:
template <size_t shape_index, size_t shape_size>
struct Looper
{
template <typename Functor>
void operator()(const std::array<int, shape_size>& shape, Functor functor)
{
for (int index = 0; index < shape[shape_index]; ++index)
{
Looper<shape_index + 1, shape_size>()
(
shape,
[index, &functor](auto... tail){ functor(index, tail...); }
);
}
}
};
template <size_t shape_size>
struct Looper<shape_size, shape_size>
{
template <typename Functor>
void operator()(const std::array<int, shape_size>&, Functor functor)
{
functor();
}
};
template <size_t shape_size, typename Functor>
void loop(const std::array<int, shape_size>& shape, Functor functor)
{
Looper<0, shape_size>()(shape, functor);
}
Example of use:
constexpr size_t N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
void f(int i, int j, int k, int l)
{
std::cout
<< std::setw(5) << i
<< std::setw(5) << j
<< std::setw(5) << k
<< std::setw(5) << l
<< std::endl;
}
// ...
loop(shape, f);
Live demo

Sorting vector based on tuple value

I have below data structure,
typedef vector< tuple<int,int,int> > vector_tuple;
In vector i am storing tuple<value,count,position>
I want to sort my vector based on count, If count is same then based on position sort the vector.
structure ordering
{
bool ordering()(....)
{
return /// ?
}
};
int main()
{
std::vector<int> v1{1,1,1,6,6,5,4,4,5,5,5};
std::vector<int> v2(v1);
vector_tuple vt;
std::tuple<int,int,int> t1;
std::vector<int>::iterator iter;
int sizev=v1.size();
for(int i=0; i < sizev ; i++)
{
auto countnu = count(begin(v2),end(v2),v1[i]);
if(countnu > 0)
{
v2.erase(std::remove(begin(v2),end(v2),v1[i]),end(v2));
auto t = std::make_tuple(v1[i], countnu, i);
vt.push_back(t);
}
}
sort(begin(vt),end(vt),ordering(get<1>vt); // I need to sort based on count and if count is same, sort based on position.
for (int i=0; i < vt.size(); i++)
{
cout << get<0>(vt[i]) << " " ;
cout << get<1>(vt[i]) << " " ;
cout << get<2>(vt[i]) << " \n" ;
}
}
Your compare method should look like:
auto ordering = [](const std::tuple<int, int, int>& lhs,
const std::tuple<int, int, int>& rhs) {
return std::tie(std::get<1>(lhs), std::get<2>(lhs))
< std::tie(std::get<1>(rhs), std::get<2>(rhs));
};
std::sort(std::begin(vt), std::end(vt), ordering);
All credit to Jarod42 for the std::tie answer.
Now let's make it generic by creating a variadic template predicate:
template<std::size_t...Is>
struct tuple_parts_ascending
{
template<class...Ts>
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return sort_order(l) < sort_order(r);
}
};
which we can invoke thus:
sort(begin(vt),end(vt),tuple_parts_ascending<1,2>());
Full Code:
#include <vector>
#include <algorithm>
#include <tuple>
#include <iostream>
using namespace std;
typedef std::vector< std::tuple<int,int,int> > vector_tuple;
template<std::size_t...Is>
struct tuple_parts_ascending
{
template<class...Ts>
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return sort_order(l) < sort_order(r);
}
};
int main()
{
std::vector<int> v1{1,1,1,6,6,5,4,4,5,5,5};
std::vector<int> v2(v1);
vector_tuple vt;
std::tuple<int,int,int> t1;
std::vector<int>::iterator iter;
int sizev=v1.size();
for(int i=0; i < sizev ; i++)
{
auto countnu = count(begin(v2),end(v2),v1[i]);
if(countnu > 0)
{
v2.erase(std::remove(begin(v2),end(v2),v1[i]),end(v2));
auto t = std::make_tuple(v1[i], countnu, i);
vt.push_back(t);
}
}
sort(begin(vt),end(vt),tuple_parts_ascending<1,2>());
for (int i=0; i < vt.size(); i++)
{
cout << get<0>(vt[i]) << " " ;
cout << get<1>(vt[i]) << " " ;
cout << get<2>(vt[i]) << " \n" ;
}
}
Expected results:
6 2 3
4 2 6
1 3 0
5 4 5
Going further, we could make this operation a little more generic and 'library-worthy' by allowing the ordering predicate and the indices to be passed as parameters (this solution required c++14):
namespace detail {
template<class Pred, std::size_t...Is>
struct order_by_parts
{
constexpr
order_by_parts(Pred&& pred)
: _pred(std::move(pred))
{}
template<class...Ts>
constexpr
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
constexpr
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return _pred(sort_order(l), sort_order(r));
}
private:
Pred _pred;
};
}
template<class Pred, size_t...Is>
constexpr
auto order_by_parts(Pred&& pred, std::index_sequence<Is...>)
{
using pred_type = std::decay_t<Pred>;
using functor_type = detail::order_by_parts<pred_type, Is...>;
return functor_type(std::forward<Pred>(pred));
}
Now we can sort like so:
sort(begin(vt),end(vt),
order_by_parts(std::less<>(), // use predicate less<void>
std::index_sequence<1, 2>())); // pack indices into a sequence
Using lambdas:
std::sort(std::begin(vt),std::end(vt),[](const auto& l,const auto& r){
if(std::get<1>(l)== std::get<1>(r)){
return std::get<2>(l) < std::get<2>(r);
}
return std::get<1>(l) < std::get<1>(r);
});

boost bimap with unordered_set_of and custom types

I want to create a bidirectional map between custom classes using bimap, this is what I do (class A and B are simplifications, they don't store just integers):
class A
{
private:
int value1;
int value2;
public:
int get_value1() const { return this->value1;}
int get_value2() const { return this->value2;}
A(int value1, int value2): value1(value1), value2(value2) {};
};
struct AHash
{
size_t operator()(const A& a) const {
size_t seed = 0;
hash_combine(seed, a.get_value1());
hash_combine(seed, a.get_value2());
return seed;
}
};
struct AComp
{
bool operator()(const A& lhs, const A& rhs) const {
return lhs.get_value1() == rhs.get_value1() &&
lhs.get_value2() == rhs.get_value2();
}
};
Class B same as A, then I created the map:
typedef bimap<
unordered_set_of<A, AHash, AComp>,
unordered_set_of<B, BHash, BComp>
> CustomMap;
CustomMap my_map;
It compiles but crashes without a meaningful log.
Any clue about what I'm doing wrong?
BTW: I'm using c++03
I suspect you have undefined behaviour elsewhere (e.g. memory management, or the actual types A and B). Here's my own self-contained test based on your sample with a lot of random insertions and lookups:
Live On Coliru
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <iostream>
#include <boost/random.hpp> // for test
#include <boost/range/empty.hpp>
#include <boost/range/iterator_range.hpp>
template <typename>
class Obj
{
private:
int value1;
int value2;
boost::tuple<int const&, int const&> key() const { return boost::tie(value1, value2); }
public:
int get_value1() const { return this->value1;}
int get_value2() const { return this->value2;}
Obj(int value1, int value2): value1(value1), value2(value2) {};
struct Hash {
size_t operator()(const Obj& a) const {
size_t seed = 0;
boost::hash_combine(seed, a.get_value1());
boost::hash_combine(seed, a.get_value2());
return seed;
}
};
struct Equality {
bool operator()(const Obj& lhs, const Obj& rhs) const {
return lhs.key() == rhs.key();
}
};
};
typedef Obj<struct TagA> A;
typedef Obj<struct TagB> B;
int myrandom() {
static boost::mt19937 prng(42);
static boost::uniform_int<> dist(0, 1000);
return dist(prng);
}
int main() {
typedef boost::bimaps::bimap<
boost::bimaps::unordered_set_of<A, A::Hash, A::Equality>,
boost::bimaps::unordered_set_of<B, B::Hash, B::Equality>
> CustomMap;
CustomMap map;
int dupes = 0;
for (int i=0; i < 10000; ++i)
{
A a(myrandom(), myrandom());
B b(myrandom(), myrandom());
if (!map.insert(CustomMap::value_type(a, b)).second)
++dupes;
}
std::cout << dupes << " duplicate insertions were skipped\n";
int left_hits = 0;
for (int i=0; i <= 10000; ++i)
if (!boost::empty(boost::make_iterator_range(map.left.equal_range(A(i,i)))))
++left_hits;
int right_hits = 0;
for (int i=0; i <= 10000; ++i)
if (!boost::empty(boost::make_iterator_range(map.right.equal_range(B(i,i)))))
++right_hits;
std::cout << "Random hits (left, right): (" << left_hits << ", " << right_hits << ")\n";
}
Prints (for the given seed and random implementation):
112 duplicate insertions were skipped
Random hits (left, right): (11, 7)
It runs clean under valgrind even in optimized builds.