How to have a tuple as both the key and value of an unordered map using a hash function or boost? - boost

I am trying to use a tuple<string, string, string> that will be placed as both the key and value of the unordered map as such:
unordered_map < tuple<string, string, string>, tuple<string, string, string>, hash_tuple> songInfo;
I understand I'm supposed to define a hash function because C++ does not have a hasher for std::tuple. However, I'm struggling to implement this through the explanations I've been reading on the other stack overflow posts. This is what my code has so far:
#include <iostream>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <tuple>
using namespace std;
typedef std::tuple<string, string, string> t;
struct hash_tuple : public unary_function <t, size_t> {
size_t operator()(const t& x) const
{
return get<0>(x) ^ get<1>(x) ^ get<2>(x);
}
};
typedef unordered_map <t, t, hash_tuple> songInfo;
int main() {
string filePath = "../data/songInfo.txt";
fstream songFile;
songFile.open("songInfo.txt");
string line;
string name, artist, date, duration, genre, mood;
vector <string> store;
while (getline(songFile, line, ',')) {
store.push_back(line);
tuple <string, string, string> iD(store[0], store[1], store[2]);
tuple <string, string, string> info(store[3], store[4], store[5]);
songInfo[iD] = info;
}
for (auto it = songInfo.begin(); it != songInfo.end(); it++)
cout << "[" << get<0>(it->first) << ", " << get<1>(it->first) << ", " <<
get<2>(it->first) << "] ==>" << get<0>(it->second) << ", " << get<1>(it-
>second) << ", " << get<2>(it->second) << endl;
}

Okay "fixing" the problem is easy: you wanted to XOR-combine hashes, not strings:
struct hash_tuple {
size_t operator()(const t& x) const {
std::hash<std::string> h{};
return h(get<0>(x)) ^ h(get<1>(x)) ^ h(get<2>(x));
}
};
Note that using namespace std is frowned upon, using declarations trump typedefs and unary_function<> is deprecated. Next up there were some syntax errors.
Combining fixes for these: Live On Coliru
#include <fstream>
#include <iostream>
#include <tuple>
#include <unordered_map>
#include <vector>
using t = std::tuple<std::string, std::string, std::string>;
struct hash_tuple {
size_t operator()(const t& x) const {
std::hash<std::string> h{};
return h(get<0>(x)) ^ h(get<1>(x)) ^ h(get<2>(x));
}
};
using SongInfo = std::unordered_map<t, t, hash_tuple>;
int main() {
std::string filePath = "songInfo.txt";
std::fstream songFile;
songFile.open("songInfo.txt");
std::string line;
std::string name, artist, date, duration, genre, mood;
std::vector<std::string> store;
SongInfo songInfo;
while (getline(songFile, line, ',')) {
store.push_back(line);
std::tuple<std::string, std::string, std::string> iD(store[0], store[1], store[2]);
std::tuple<std::string, std::string, std::string> info(store[3], store[4], store[5]);
songInfo[iD] = info;
}
for (auto it = songInfo.begin(); it != songInfo.end(); it++)
std::cout << "[" << get<0>(it->first) << ", " << get<1>(it->first)
<< ", " << get<2>(it->first) << "] ==>" << get<0>(it->second)
<< ", " << get<1>(it->second) << ", " << get<2>(it->second)
<< std::endl;
}

Related

How to make recursive Spirit X3 parser with a separate visitor class

A parser application where I’m working on calls for recursive rules. Besides looking into the Recursive AST tutorial examples of Boost Spirit X3 which can be found here:
https://www.boost.org/doc/libs/develop/libs/spirit/doc/x3/html/index.html, I was looking for a solution with a std::variant of some types as well as a std::vector of that same
variant type.
In the StackOverflow post titled: Recursive rule in Spirit.X3, I found the code from the answer from sehe a decent starting point for my parser.
I have repeated the code here but I have limited the input strings to be tested. Because the full list from the original is not relevant for this question here.
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>>
{
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
friend std::ostream& operator<<(std::ostream& os, base_type const& v) {
struct {
std::ostream& operator()(float const& f) const { return _os << "float:" << f; }
std::ostream& operator()(int const& i) const { return _os << "int:" << i; }
std::ostream& operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) _os << el << ",";
return _os << ']';
}
std::ostream& _os;
} vis { os };
return std::visit(vis, v);
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def = "tuple" >> x3::lit(':') >> ("[" >> value_ % "," >> "]");
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point = x3::skip(x3::space) [ value_ ];
}
int main()
{
for (std::string const str : {
"float: 3.14",
"int: 3",
"tuple: [float: 3.14,int: 3]",
"tuple: [float: 3.14,int: 3,tuple: [float: 4.14,int: 4]]"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
std::cout << "Parsed '" << val << "'\n";
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}
However I would like to use a traditional visitor class rather than making ostream a friend in the variant class. You know just a struct/class with a bunch of function objects for each type you encounter in the variant and a "for loop" for the vector that calls std::visit for each
element.
My goal for the traditional visitor class is to be able to maintain a state machine during printing.
My own attempts to write this visitor class did fail because I ran into an issue with my GCC 8.1 compiler. With GCC during compilation std::variant happens to be std::variant_size somehow and I got the following error:
error: incomplete type 'std::variant_size' used in nested name specifier
More about this here:
Using std::visit on a class inheriting from std::variant - libstdc++ vs libc++
Is it possible giving this constraint on GCC to write a visitor class for the code example I included, so that the ostream stuff can be removed?
Is it possible giving this constraint on GCC to write a visitor class for the code example I included, so that the ostream stuff can be removed?
Sure. Basically, I see three approaches:
1. Add the template machinery
You can specialize the implementation details accidentally required by GCC:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
};
namespace std {
template <> struct variant_size<value> :
std::variant_size<value::base_type> {};
template <size_t I> struct variant_alternative<I, value> :
std::variant_alternative<I, value::base_type> {};
}
See it live on Wandbox (GCC 8.1)
2. Don't (again live)
Extending the std namespace is fraught (though I think it's legal for
user-defined types). So, you can employ my favorite pattern and hide th
estd::visit dispatch in the function object itself:
template <typename... El>
void operator()(std::variant<El...> const& v) const { std::visit(*this, v); }
Now you can simply call the functor and it will automatically dispatch
on your own variant-derived type because that operator() overload does
NOT have the problems that GCC stdlib has:
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
3. Make things explicit
I like this the least, but it does have merit: there's no magic and no
tricks:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
// ...
Again, live
SUMMARY
After thinking a bit more, I'd recommend the last approach, due to the relative simplicity. Clever is often a code-smell :)
Full listing for future visitors:
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
std::ostream& _os;
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
void operator()(float const& f) const { _os << "float:" << f; }
void operator()(int const& i) const { _os << "int:" << i; }
void operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) {
operator()(el);
_os << ",";
}
_os << ']';
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def = "tuple" >> x3::lit(':') >> ("[" >> value_ % "," >> "]");
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point = x3::skip(x3::space) [ value_ ];
}
int main()
{
for (std::string const str : {
"float: 3.14",
"int: 3",
"tuple: [float: 3.14,int: 3]",
"tuple: [float: 3.14,int: 3,tuple: [float: 4.14,int: 4]]"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}

MultiIndex Container equal_range .. get output in reverse order

I have a boost::multiIndex container.
say :
typedef boost::multi_index<....
> OrderSet;
OrderSet orderSet_;
int main()
{
const auto it = orderSet_.get<0>().equal_range(boost::make_tuple(/* Some Values*/))
if(it.first != it.second)
while(it.second != it.first) { /* Somethings to do */;
--it.second;
}
}
the program crash with offset_ptr error.
for the program it has value on increasing order. so I want highest value first then so-on..
Is any a over-loaded function of boost::equal_range(..., [&](const auto a, const auto b)-> decltype bool{return a > b;});
Something like this. it's like reverse_iterator of equal_range()
UPDATE: multi-Index container is accessed by one producer and many consumer. while consumer is finding equal_range, producer add or delete elements and consumer throw the error... this is only happens when i am reverse iterating...
You're leaving out the essential part: the chosen index type.
Different index types afford different interfaces.
Then again, equal_range implies a ordered or unordered map. And because reversing the order on an unordered map is non-sense, I'm going to assume an ordered map.
Next, with make_tuple there I'm guessing composite keys.
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
struct X {
int i;
std::string name;
};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, std::string, &X::name>
>
>
>
> OrderSet;
Then here's the native order:
#include <iostream>
int main()
{
std::cout << std::unitbuf;
OrderSet orderSet_ {
{ 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
};
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// ...
And I'd use Boost Range to get the reverse order:
#include <boost/range/adaptor/reversed.hpp>
// ...
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
BONUS TAKE
Of course you can write the same manually:
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
--it.second;
auto& el = *it.second;
std::cout << el.i << "," << el.name << "; ";
}
Live Demo
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>
struct X {
int i; // = [] { static int gen = 0; return ++gen; }();
std::string name;
};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, std::string, &X::name>
>
>
>
> OrderSet;
#include <iostream>
int main()
{
std::cout << std::unitbuf;
OrderSet orderSet_ {
{ 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
};
{
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
}
Prints
2,five; 2,three;
Now in reverse:
2,three; 2,five;
Also in reverse:
2,three; 2,five;
Even further out on a limb, since you said offset_ptr you might be using Boost Interprocess allocators.
Here's a demo that shows how you'd do the above correctly in a memory mapped/shared memory area:
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
namespace bmi = boost::multi_index;
namespace bip = boost::interprocess;
//namespace Shared { struct X; }
//namespace std { template<typename Alloc> struct uses_allocator<Shared::X, Alloc> : std::true_type {}; }
namespace Shared {
using Segment = bip::managed_mapped_file;
template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;
struct X {
using allocator_type = Alloc<char>;
template <typename Alloc>
X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}
int i;
String name;
};
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, String, &X::name>
>
>
>,
Alloc<X>
> OrderSet;
}
#include <iostream>
int main()
{
std::cout << std::unitbuf;
Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);
auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());
if (orderSet_.empty()) {
// can't get multi-index to use the scoped allocator "magically" :(
orderSet_.emplace(1, "one", orderSet_.get_allocator());
orderSet_.emplace(1, "one", orderSet_.get_allocator());
orderSet_.emplace(1, "two", orderSet_.get_allocator());
orderSet_.emplace(2, "three", orderSet_.get_allocator());
orderSet_.emplace(3, "four", orderSet_.get_allocator());
orderSet_.emplace(2, "five", orderSet_.get_allocator());
}
{
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
std::cout << "\nBye\n";
}
Prints
2,five; 2,three;
Now in reverse:
2,three; 2,five;
Also in reverse:
2,three; 2,five;
Bye
Twice (proving all data was correctly in the shared memory segment).
BONUS TAKE
Apparently, Boost Multi-Index doesn't quite play completely well with the scoped allocator, because it would be more elegant with that:
Live On Coliru
#include <set>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container/set.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/iterator_range.hpp>
namespace bip = boost::interprocess;
namespace Shared {
using Segment = bip::managed_mapped_file;
template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;
struct X {
using allocator_type = Alloc<char>;
template <typename Alloc>
X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}
bool operator<(X const& other) const { return i < other.i; }
bool operator<(int other) const { return i < other; }
int i;
String name;
};
template <typename T>
using Multiset = boost::container::multiset<
T,
std::less<T>,
boost::container::scoped_allocator_adaptor<Alloc<X> >
>;
using OrderSet = Multiset<X>;
}
#include <iostream>
int main()
{
std::cout << std::unitbuf;
Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);
auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());
if (orderSet_.empty()) {
// scoped-allocator automatically propagates to the string
orderSet_.emplace(1, "one");
orderSet_.emplace(1, "one");
orderSet_.emplace(1, "two");
orderSet_.emplace(2, "three");
orderSet_.emplace(3, "four");
orderSet_.emplace(2, "five");
}
{
auto const range = orderSet_.equal_range({2, "", orderSet_.get_allocator()});
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.equal_range({2, "", orderSet_.get_allocator()});
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
std::cout << "\nBye\n";
}

boost spirit debug rule with locals

I fail to compile code in debug mode (code with BOOST_SPIRIT_DEBUG_NODE(my_rule)) when my_rule has some local variable of custom type.
First version with rule qi::locals<std::string> is OK
Second version with rule qi::locals<std::string,int> is still OK
Current version with rule qi::locals<std::string,std::vector<int> > does not compile.
error: no match for operator<< (operand types are std::basic_ostream<char> and const std::vector<int>)
I declare streaming operator<< :
std::ostream& > operator<< (std::ostream& os, std::vector<int> const& art)
But It still does not compile.
I use boost 1_64_0. Here is the smallest complete code:
#define BOOST_SPIRIT_DEBUG
#if !defined(BOOST_SPIRIT_DEBUG_OUT)
#define BOOST_SPIRIT_DEBUG_OUT std::cerr
#endif
#include <tuple>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <iostream>
#include <string>
#include <vector>
// To solve the pb of declaration of grammar with locals
#include <typeinfo>
std::ostream&
operator<< (std::ostream& os, std::vector<int> const& art)
{
os << "[";
for( auto it = art.begin(); it != art.end() ; it++ ) {
os << *it << ",";
}
os << "]";
return os;
}
namespace client
{
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using phoenix::val;
using namespace qi::labels;
using qi::_val;
using qi::_1;
// Our number list parser
template <typename Iterator>
struct mini_wkart_grammar
// first version: : qi::grammar<Iterator, int(), qi::locals<std::string>, ascii::space_type>
// second version: : qi::grammar<Iterator, int(), qi::locals<std::string,int>, ascii::space_type>
: qi::grammar<Iterator, std::vector<int>(), qi::locals<std::string,std::vector<int> >, ascii::space_type>
{
mini_wkart_grammar() : mini_wkart_grammar::base_type(start,"numbers")
{
using phoenix::push_back;
// first version: start= (qi::int_ >> qi::char_(',') >> qi::int_)[_val=_1+_3];
// second version: start= (qi::int_[_b=_1] >> qi::char_(',') >> qi::int_[_b+=_1])[_val=_b];
start= (qi::int_[push_back(_b,_1)] >> qi::char_(',') >> qi::int_[push_back(_b,_1)])[_val=_b];
BOOST_SPIRIT_DEBUG_NODE(start);
}
// first version OK: qi::rule<Iterator, int(), qi::locals<std::string>, ascii::space_type> start;
// second version OK: qi::rule<Iterator, int(), qi::locals<std::string,int>, ascii::space_type> start;
qi::rule<Iterator, std::vector<int>(), qi::locals<std::string,std::vector<int> >, ascii::space_type> start;
};
}
////////////////////////////////////////////////////////////////////////////
// Main program
////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "\t\tA comma separated list parser for Spirit...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Give me a comma separated list of numbers.\n";
std::cout << "Type [q or Q] to quit\n\n";
// std::string result;
// first ans second version: int result;
std::vector<int> result;
std::string str;
using boost::spirit::ascii::space;
client::mini_wkart_grammar<std::string::const_iterator> wkart_grammar;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
// if (client::parse_numbers(str.begin(), str.end()))
if (boost::spirit::qi::phrase_parse(iter, end, wkart_grammar, space, result))
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << result << " Parses OK: " << std::endl;
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
I think miss something in the operator declaration?
Thanks for any help..
First Off...
What are you trying to achieve anyways? That whole grammar could be start = qi::int_ % ','; and still have the exact same effect. See Boost Spirit: “Semantic actions are evil”?
Your Question:
Sadly you need to make that operator<< ADL-enabled. (http://en.cppreference.com/w/cpp/language/adl)
Since the element type is primitive, there is no associated namespace. So the only namespace that will be tried is namespace ::std which declared std::vector<>.
namespace std {
std::ostream &operator<<(std::ostream &os, vector<int> const &art) {
os << "[";
for (auto it = art.begin(); it != art.end(); it++) {
os << *it << ",";
}
os << "]";
return os;
}
}
That might have undesired side effects, you you may want to force the issue with a hack:
namespace ADL_Hack {
template <typename T>
struct allocator : std::allocator<T> { };
}
template <typename T>
using Vector = std::vector<T, ADL_Hack::allocator<T> >;
namespace ADL_Hack {
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, std::vector<Ts...> const &art) {
os << "[";
for (auto it = art.begin(); it != art.end(); it++) {
os << *it << ",";
}
os << "]";
return os;
}
}
See it Live On Wandbox

How to pass a char to `boost::char_separator<char>`

Based on How do I tokenize a string in C++?
explicit char_separator(const Char* dropped_delims,
const Char* kept_delims = "",
empty_token_policy empty_tokens = drop_empty_tokens)
#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
using namespace std;
using namespace boost;
int main(int, char**)
{
string text = "token, test string";
char_separator<char> sep(", ");
tokenizer< char_separator<char> > tokens(text, sep);
BOOST_FOREACH (const string& t, tokens) {
cout << t << "." << endl;
}
}
I need to pass in a char as the separator as follows:
void splitString(const string& text, char sepChar)
{
char_separator<char> sep(&sepChar);
tokenizer< char_separator<char> > tokens(text, sep);
BOOST_FOREACH (const string& t, tokens) {
cout << t << "." << endl;
}
}
Question> Is this right way to convert char to const char* for boost::char_separator?
Thank you

Error including boost/spirit/include/qi.hpp

I'm having the same error as occurs here. See 'compilation info' at the bottom for the long error message. Basically if I #include <boost/spirit/include/qi.hpp> I can't compile. Totally stumped by this one... I am compiling with g++ 4.9.3 on Debian using C++11. For reference the first part of the error message is:
In file included from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:35:0,
from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:20,
from /usr/include/boost/spirit/include/qi.hpp:16,
from prog.cpp:9:
/usr/include/boost/spirit/home/qi/reference.hpp: In instantiation of 'bool boost::spirit::qi::reference<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil_>, boost::spirit::locals<> >; Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >; Attribute = std::basic_string<char>; Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>]':
My code is actually a little bit different to the above example:
My::Dictionary Parser::parse( const char * s ) {
std::string input(s); // input to parse
qi_my_protocol grammar; // create instance of parser
My::Dictionary msg; // map to receive results
bool result = qi::phrase_parse(
input.begin(),
input.end(),
grammar,
qi::space,
msg
); // returns true if successful
return msg;
}
Your string isn't const, so the iterators first and last aren't const iterators.
Either make the my_Parse function not a template (after all, you hardcode the iterator type on the grammar to be std::string::const_iterator anyways), or instantiate the grammar with the actual iterator type:
my_grammar<Iterator> g;
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <stdio.h>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
template <typename Iterator>
struct my_grammar : boost::spirit::qi::grammar<Iterator, std::string(), ascii::space_type>
{
my_grammar() : my_grammar::base_type(start)
{
using qi::alpha;
using qi::alnum;
start %=
(+alpha | +alnum)
;
}
qi::rule<Iterator, std::string(), ascii::space_type> start;
};
template <typename Iterator>
bool my_Parse(Iterator first, Iterator last, std::string& result)
{
using boost::spirit::ascii::space;
my_grammar<Iterator> g;
bool r = phrase_parse(first, last, g, space, result);
if (!r || first != last) // fail if we did not get a full match
return false;
return r;
}
int main() {
std::string str;
while (getline(std::cin, str))
{
std::string result = "";
if (my_Parse(str.begin(), str.end(), result))
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "got: " << result << std::endl;
std::cout << "\n-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
}
}

Resources