Why is this boost::variant example not working? - c++

I am getting to know boost::variant. I think this example should work.
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/sequence.hpp>
#include <boost/variant/variant.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <boost/variant/get.hpp>
boost::variant< bool,long,double,std::string,
std::vector<boost::variant<bool> > > v4;
void main()
{
std::vector<boost::variant<bool> > av (1);
v4= av;
try
{
bool b=
boost::get<bool> (v4[0]); // <--- this is line 20
std::cout << b;
}
catch (boost::bad_get v)
{
std::cout << "bad get" <<std::endl;
}
}
I get a compilation error:
d:\m\upp\boosttest\main.cpp(20) : error C2676: binary '[' : 'boost::variant' do
es not define this operator or a conversion to a type acceptable to the predefined operator
with
[
T0_=bool,
T1=long,
T2=double,
T3=std::string,
T4=std::vector>
]

v4[0] is not valid since v4 is a variant, not a vector. You need to use boost::get to retrieve the vector stored in it first. So, line 20 should be
boost::get<bool>(boost::get<std::vector<boost::variant<bool> > >(v4)[0]);

Related

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

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';
}

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

C2061: syntax error : identifier 'string' - Behaving weird

I am trying to learn C++, however, the parameter to a method I have in my own class is misbehaving. When it uses a dataType of 'int', it works fine with no errors, but when I attempt to change it to a 'string' dataType, the program crashes with this error.
Error 1 error C2061: syntax error : identifier 'string' in temp.h ln
8 col 1
The classes I am using are as follows:
WORKING CODE
TesterClass.cpp // Entry Point
#include "stdafx.h"
#include "Temp.h"
int _tmain(int argc, _TCHAR* argv[])
{
Temp tmp;
tmp.doSomething(7);
return 0;
}
Temp.h
#pragma once
class Temp
{
public:
Temp();
void doSomething(int blah);
};
Temp.cpp
#include "stdafx.h"
#include "Temp.h"
#include <iostream>
#include <string>
using std::string;
Temp::Temp()
{
std::cout << "Entry" << std::endl;
string hi;
std::cin >> hi;
std::cout << hi << std::endl;
}
void Temp::doSomething(int blah)
{
std::cout << blah;
}
BROKEN CODE
Temp.h
#pragma once
class Temp
{
public:
Temp();
void doSomething(string blah);
};
Temp.cpp
#include "stdafx.h"
#include "Temp.h"
#include <iostream>
#include <string>
using std::string;
Temp::Temp()
{
std::cout << "Entry" << std::endl;
string hi;
std::cin >> hi;
std::cout << hi << std::endl;
}
void Temp::doSomething(string blah)
{
std::cout << blah;
}
When I adjust the parameter 'blah' to be a string, in both the .h and .cpp file, the problem occurs.
I have looked around, but none of the answers seem to solve my problem. I would greatly love help on this an I am out of ideas. I have tried reinstalling C++, messing with:
using namepace std;
using std::string;
std::string instead of string
etc.
If you know how to solve my problem I would love to hear from you. I am more than happy to provide more information.
C++ performs single-pass compilation, so std::string needs to be declared before you use it at all - including in the header file.
// Temp.h
#pragma once
#include <string>
class Temp
{
public:
Temp();
void doSomething(std::string blah);
};
I would encourage you to be specific in your header files when specifying classes like this, because you might easily come across another library that defines it's own string and then you would run into naming conflicts. Save the using import statements for your cpp files.
πάντα ῥεῖ had the write answer, thankyou!
They said to use std::string when needed, and to also #include <string> in the header file.

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