Struggling to create a Boost-Bimap containing std::bitset - c++

I have a number of strings and their bitset equivalents. I need to be able to look up equivalents in both directions, i.e. "str to bitset" and "bitset to str". I believe boost-bimap would be the right container for this job.
I managed to get this to work with strings and integers but my string / bitset bimap does not compile. I am using VS2019 with the latest boost release.
Integer example works:
#include <boost/bimap.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::bimap<std::string, int> bimap_str_int_t;
bimap_str_int_t bimap1;
bimap1.insert(bimap_str_int_t::value_type("A", 1));
std::cout << bimap1.left.at("A") << '\n'; //prints 1
std::cout << bimap1.right.at(1) << '\n'; // prints A
}
Bitset example fails to compile:
#include <boost/bimap.hpp>
#include <string>
#include <iostream>
#include <bitset>
int main()
{
typedef std::bitset<3> bitset_t;
typedef boost::bimap<std::string, bitset_t> bimap_str_bitset_t;
bimap_str_bitset_t bimap2;
bitset_t bits{ "010" };
bimap2.insert(bimap_str_bitset_t::value_type("A", bits));
std::cout << bimap2.left.at("A") << '\n';
std::cout << bimap2.right.at(bits) << '\n';
}
The bitset example creates the following compiler error:
boost_test.cpp(20): message : see reference to class template instantiation 'boost::bimaps::bimap' being compiled
I am not sure how to fix this and would greatly appreciate any hints.

The issue is that std::bitset has no operator< - one of the requirements of any STL-like ordered collection.
To fix this, you need to supply a comparison function - here's one way you might try:
#include <boost/bimap.hpp>
#include <string>
#include <iostream>
#include <bitset>
typedef std::bitset<3> bitset_t;
struct compare_bitset {
bool operator()(const bitset_t& x, const bitset_t& y) const {
return x.to_ulong() < y.to_ulong();
}
};
int main()
{
using bitset_set = boost::bimaps::set_of<bitset_t, compare_bitset>;
typedef boost::bimap < std::string, bitset_set> bimap_str_bitset_t;
bimap_str_bitset_t bimap2;
bitset_t bits{ "010" };
bimap2.insert(bimap_str_bitset_t::value_type("A", bits));
std::cout << bimap2.left.at("A") << '\n';
std::cout << bimap2.right.at(bits) << '\n';
}

Related

How do I fix the issue where Visual Studios doesn't recognize the class type of the array when size() is called?

When I try to find the size of an array, Visual Studio returns the error that the identifier doesn't have a class type. I think this might be due to corruption.
#include <iostream>
#include <array>
using namespace std;
int arr[] = {1,2,3};
int main()
{
cout << arr.size() << endl;
}
C-style arrays do not have member methods, such as size(). Standard containers, like std::array and std::vector, have size() methods, eg:
#include <iostream>
#include <array>
std::array<int, 3> arr{1,2,3};
int main()
{
std::cout << arr.size() << std::endl;
}
#include <iostream>
#include <vector>
std::vector<int> arr{1,2,3};
int main()
{
std::cout << arr.size() << std::endl;
}
There is also a std::size() function, which has overloads to work with standard containers, as well as C-style arrays, eg:
#include <iostream>
#include <array>
int arr[] = {1,2,3};
int main()
{
std::cout << std::size(arr) << std::endl;
}
You declared a C-array, which is not a class, and does not have a size() member.
You wanted to declare a std::array<int, 3> arr{1, 2, 3}; and then you would have access to the size() function.
Link to the relevant page on cppreference.
The C array you are using is different from an std::array.
The C++ standard library class std::array has the class member function size.
You are probably looking for something like this :
#include <iostream>
#include <array>
int main()
{
std::array<int,3> numbers {1, 2, 3};
std::cout << numbers.size() << '\n';
}

std::variant cout in C++

I am relatively new to CPP and have recently stumbled upon std::variant for C++17.
However, I am unable to use the << operator on such type of data.
Considering
#include <iostream>
#include <variant>
#include <string>
using namespace std;
int main() {
variant<int, string> a = "Hello";
cout<<a;
}
I am unable to print the output. Is there any short way of doing this? Thank you so much in advance.
You can use std::visit if you don't want to use std::get.
#include <iostream>
#include <variant>
struct make_string_functor {
std::string operator()(const std::string &x) const { return x; }
std::string operator()(int x) const { return std::to_string(x); }
};
int main() {
const std::variant<int, std::string> v = "hello";
// option 1
std::cout << std::visit(make_string_functor(), v) << "\n";
// option 2
std::visit([](const auto &x) { std::cout << x; }, v);
std::cout << "\n";
}
use std::get
#include <iostream>
#include <variant>
#include <string>
using namespace std;
int main() {
variant<int, string> a = "Hello";
cout << std::get<string>(a);
}
If you want to get automatically, it can't be done without knowing its type. Maybe you can try this.
string s = "Hello";
variant<int, string> a = s;
cout << std::get<decltype(s)>(a);
#include <iostream>
#include <variant>
#include <string>
int main( )
{
std::variant<int, std::string> variant = "Hello";
std::string string_1 = std::get<std::string>( variant ); // get value by type
std::string string_2 = std::get<1>( variant ); // get value by index
std::cout << string_1 << std::endl;
std::cout << string_2 << std::endl;
//may throw exception if index is specified wrong or type
//Throws std::bad_variant_access on errors
//there is also one way to take value std::visit
}
Here is the description link: https://en.cppreference.com/w/cpp/utility/variant

Using rolling accumulators in unordered maps in a Class

I'm trying to use an unordered map to hold rolling accumulators in a class.
First let me show what works. Here is an accumulator within a class that works as expected without the map. Note that the accumulator needs to be initialized in the initialization list.
#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>
namespace nmbstacc = boost::accumulators;
typedef nmbstacc::accumulator_set<double, nmbstacc::stats<nmbstacc::tag::rolling_mean >> MACC;
class RollMean {
public:
MACC m_acc;
RollMean(void) : m_acc(nmbstacc::tag::rolling_window::window_size = 3) {}
};
int main()
{
RollMean obj;
obj.m_acc(0.5);
obj.m_acc(1.5);
obj.m_acc(2.5);
obj.m_acc(3.5);
std::cout << "roll_mean: " << nmbstacc::rolling_mean(obj.m_acc) << std::endl;
std::getchar();
return 0;
}
However, what I need is an unordered map to hold these accumulators in a class but can't seems to figure out how to get the following program to compile. I'm not sure how to declare the mainmap container without first initializing the rolling accumulator.
#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>
#include <unordered_map>
namespace nmbstacc = boost::accumulators;
typedef nmbstacc::accumulator_set<double, nmbstacc::stats<nmbstacc::tag::rolling_mean >> MACC;
class RollMean {
public:
MACC m_acc;
std::unordered_map<std::string, MACC> mainmap;
RollMean(std::string name) : m_acc(nmbstacc::tag::rolling_window::window_size = 3) {
mainmap.emplace(name, m_acc);
}
};
int main()
{
RollMean obj("a");
obj.mainmap["a"](1.0);
std::cout << "roll_mean: " << nmbstacc::rolling_mean(obj.mainmap["a"]) << std::endl;
std::getchar();
return 0;
}
I get the following error:
Error C2679 binary '[': no operator found which takes a right-hand operand of type 'boost::parameter::keyword' (or there is no acceptable conversion)
Thanks.
Like #jv_ hinted, map[key] is a mutating operation, which inserts a default constructed element if none exists.
However, there's no default constructor for your element type. Therefore, you can't use that operator.
If you use obj.mainmap.at("a") instead of obj.mainmap["a"], you'll get an exception on missing keys instead.
Live On Coliru
#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>
#include <unordered_map>
namespace nmbstacc = boost::accumulators;
typedef nmbstacc::accumulator_set<double, nmbstacc::stats<nmbstacc::tag::rolling_mean> > MACC;
class RollMean {
public:
MACC m_acc;
std::unordered_map<std::string, MACC> mainmap;
RollMean(std::string name) : m_acc(nmbstacc::tag::rolling_window::window_size = 3) { mainmap.emplace(name, m_acc); }
};
int main() {
RollMean obj("a");
obj.mainmap.at("a")(1.0);
std::cout << "roll_mean: " << nmbstacc::rolling_mean(obj.mainmap.at("a")) << std::endl;
}
Prints:
roll_mean: 1

BOOST_PP_REPEAT with boost::fusion::size

I want to iterate in compile time over struct and write to output number of iteration. Just to mention - in real case I will pass some more parameters in data.
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
struct MyStruct
{
int x;
int y;
};
BOOST_FUSION_ADAPT_STRUCT(
MyStruct,
(int, x)
(int, y)
)
#define PRINT(unused, number, data) \
std::cout << number << std::endl;
int main()
{
MyStruct s;
std::cout << boost::fusion::size(s) << std::endl;
//line below works - it iterate and write output
BOOST_PP_REPEAT(2, PRINT, "here I will pass my data")
//this won't compile
//BOOST_PP_REPEAT(boost::fusion::size(s), PRINT, "here i will pass my data")
}
How to fix problematic line so it will work when I will add more members in structure? I need solution for C++03 :(
Instead of using BOOST_PP_REPEAT, you can use the boost::fusion::for_each which goes through every element. example:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
struct MyStruct {
int x;
int y;
};
BOOST_FUSION_ADAPT_STRUCT(
MyStruct,
(int, x)
(int, y)
)
template<typename Data>
struct PrintWithData {
PrintWithData(Data data) : data(data) {}
template<typename T>
operator()(const T& thingToBePrinted)
{
std::cout << thingToBePrinted << std::endl;
}
Data data;
};
int main()
{
MyStruct s;
//this will compile
boost::fusion::for_each(s, PrintWithData<std::string>("here I will pass my data"));
}
Here is exact solution for this problem (asked more general question later, and found answear which solve this problem too): https://stackoverflow.com/a/31713778/4555790

how can I write a list of pair?

I am currently trying to write a list of pairs. my code is :
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <list>
using namespace std;
list<pair<string,char>> listPair;
list<pair<string,char>>::iterator it;
void printStars(list<pair<string,char>> listPair)
{
for (it=listPair.begin(); it != listPair.end(); it++)
cout << it->first <<" ";
cout << endl;
}
int main()
{
pair<string,char> mypair;
listPair.push_back(make_pair("bib",'a'));
listPair.push_back(make_pair("bob",'b'));
for_each(listPair.begin(), listPair.end(), printStars);
return 0;
}
Compilation fails with:
error C2664: 'void (std::list<_Ty>)' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'std::list<_Ty>'
Can you please help me detect where exactly is the problem?
The functor you pass to std::for_each is expected to accept an element of the range you pass into std::for_each. Your last has pair<string,char> elements, so your functor should have a signature like: void printStars(const pair<string,char>& elem).
In addition, to pass a plain function to std::for_each you need to use std::ref or (on an old compiler) std::ptr_fun.
#include <iostream>
#include <algorithm>
#include <list>
#include <string> // missing include
#include <utility>
#include <functional>
using namespace std;
typedef list< pair<string,char> > list_t;
list_t listPair;
void printStars(list_t::reference x) // use a reference, otherwise you create a copy
{
cout << x.first << " " << x.second << endl;
}
int main()
{
pair<string,char> mypair;
listPair.push_back(make_pair("bib",'a'));
listPair.push_back(make_pair("bob",'b'));
for_each(listPair.begin(), listPair.end(), std::ref(printStars)); // C++11
for_each(listPair.begin(), listPair.end(), std::ptr_fun(&printStars)); // C++98
return 0;
}
Your problem is, your printStars() expects a list, however for_each passes it each item, not the actual list:
Working code :
#include <iostream>
#include <algorithm>
#include <iterator>
#include <list>
#include <string>
#include <utility>
list<pair<string,char> > listPair;
list<pair<string,char> >::iterator it;
void printStars(const pair<string,char> & listPair){ //notice the &, so it would pass by reference and not make a new copy of the pair.
cout << listPair.first << ' ';
}
int main() {
pair<string,char> mypair;
listPair.push_back(make_pair("bib",'a'));
listPair.push_back(make_pair("bob",'b'));
for_each(listPair.begin(), listPair.end(), printStars);
cout << endl;
return 0;
}