I'm using boost::irange and created a helper function to simplify the code by removing the need for explicit template parameters. I don't understand why it doesn't work. Here's the code:
#include <iostream>
#include <boost/range/irange.hpp>
template<typename T>
boost::irange<T> range_from_zero(T limit)
{
return boost::irange<T>(T(), limit);
}
int main() {
size_t end = 100;
for (auto i : range_from_zero(0,end))
std::cout << i << ' ';
return 0;
}
There's a live version here https://ideone.com/VVvW6e, which produces compilation errors
prog.cpp:5:8: error: 'irange<T>' in namespace 'boost' does not name a type
boost::irange<T> range_from_zero(T limit)
^
prog.cpp: In function 'int main()':
prog.cpp:12:41: error: 'range_from_zero' was not declared in this scope
for (auto i : range_from_zero(0,end))
If I use boost::irange directly in the range-for, then it works:
#include <iostream>
#include <boost/range/irange.hpp>
int main() {
size_t end = 100;
for (auto i : boost::irange<size_t>(0,end))
std::cout << i << ' ';
return 0;
}
this works fine: https://ideone.com/TOWY6H
I thought maybe is was a problem using range-for on the return of a function, but it isn't; this works using a std::vector:
#include <iostream>
#include <boost/range/irange.hpp>
template<typename T>
std::vector<T> range_from_zero(T limit)
{
auto range = boost::irange<T>(T(), limit);
return { std::begin(range), std::end(range) };
}
int main() {
size_t end = 100;
for (auto i : range_from_zero(end))
std::cout << i << ' ';
return 0;
}
See https://ideone.com/TYRXnC
Any ideas, please?
But, first off, what's wrong with Live On Coliru
for (size_t i : irange(0, 100))
or even Live On Coliru
size_t end = 100;
for (auto i : irange(0ul, end))
irange is a function template, and it cannot be used as a return type.
The return type is integer_range or strided_integer_range. As such, irange is already the function you were looking for.
Only, you didn't pass arguments that could be unambiguously deduced. If you can to allow this, "copy" irange() implementation using separate template argument types for the boundary values and use e.g. std::common_type<T1,T2>::type as the range element.
Here's my stab at writing range_from_zero without naming implementation details in the interface:
Live On Coliru
#include <iostream>
#include <boost/range/irange.hpp>
template <typename T>
auto izrange(T upper) -> decltype(boost::irange(static_cast<T>(0), upper)) {
return boost::irange(static_cast<T>(0), upper);
}
int main() {
size_t end = 100;
for (size_t i : izrange(end))
std::cout << i << ' ';
}
Related
Scenario
I have a C++ function which intakes a parameter as std::chrono::milliseconds. It is basically a timeout value. And, it is a default parameter set to some value by default.
Code
#include <iostream>
#include <chrono>
void Fun(const std::chrono::milliseconds someTimeout = std::chrono::milliseconds(100)) {
if (someTimeout > 0) {
std::cout << "someNumberInMillis is: " << someNumberInMillis.count() << std::endl;
}
}
int main() {
unsigned int someValue = 500;
Fun(std::chrono::milliseconds(someValue))
}
Issue
All of above is okay but, when I call Fun with a value then fails to compile and I get the following error:
No viable conversion from 'bool' to 'std::chrono::milliseconds' (aka
'duration >')
Question:
What am I doing wrong here? I want the caller of Fun to be explicitly aware that it is using std::chrono::milliseconds when it invokes Fun. But the compiler doesn't seem to allow using std::chrono::milliseconds as a parameter?
How use std::chrono::milliseconds as a default parameter?
Environment
Compiler used is clang on macOS High Sierra
With the other syntax errors fixed, this compiles without warnings in GCC 9:
#include <iostream>
#include <chrono>
void Fun(const std::chrono::milliseconds someNumberInMillis
= std::chrono::milliseconds(100))
{
if (someNumberInMillis > std::chrono::milliseconds{0}) {
std::cout << "someNumberInMillis is: " << someNumberInMillis.count()
<< std::endl;
}
}
int main()
{
unsigned int someValue = 500;
Fun(std::chrono::milliseconds(someValue));
}
I have a more complex rule, but this one will suffice for this question (I hope). Consider the rule:
result = double_ >> *(char_ > int_);
where result is declared in terms of a struct result in namespace ast:
qi::rule<Iterator, ast::result(), qi::space_type> result;
Then how does ast::result have to look like?
According to the boost::spirit docs (http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/spirit/abstracts/attributes/compound_attributes.html), the attribute of
char_ > int_ is tuple<char, int> or std::pair<char, int>.
So, I tried:
namespace ast
{
using second_type = std::vector<std::pair<char, int>>;
struct result
{
double first;
second_type second;
};
} // namespace ast
in addition to
BOOST_FUSION_ADAPT_STRUCT(
ast::result,
(double, first),
(ast::second_type, second)
)
But this gives me the compile error:
error: no matching function for call to 'std::pair<char, int>::pair(const char&)'
This rule is simple, creating the AST struct that the result will be stored in should be simple too... but how?
Here is a complete test program with my attempt:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace ast
{
using second_type = std::vector<std::pair<char, int>>;
struct result
{
double first;
second_type second;
friend std::ostream& operator<<(std::ostream& os, result const& result);
};
std::ostream& operator<<(std::ostream& os, second_type::value_type val)
{
return os << val.first << ' ' << val.second;
}
std::ostream& operator<<(std::ostream& os, result const& result)
{
os << result.first;
for (auto& i : result.second)
os << ' ' << i;
return os;
}
} // namespace ast
BOOST_FUSION_ADAPT_STRUCT(
ast::result,
(double, first),
(ast::second_type, second)
)
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
class test_grammar : public qi::grammar<Iterator, ast::result(), qi::space_type>
{
private:
qi::rule<Iterator, ast::result(), qi::space_type> result;
public:
test_grammar() : test_grammar::base_type(result, "result_grammar")
{
using qi::double_;
using qi::char_;
using qi::int_;
result = double_ >> *(char_ > int_);
}
};
} // namespace client
int main()
{
std::string const input{"3.4 a 5 b 6 c 7"};
using iterator_type = std::string::const_iterator;
using test_grammar = client::test_grammar<iterator_type>;
namespace qi = boost::spirit::qi;
test_grammar program;
iterator_type iter{input.begin()};
iterator_type const end{input.end()};
ast::result out;
bool r = qi::phrase_parse(iter, end, program, qi::space, out);
if (!r || iter != end)
{
std::cerr << "Parsing failed." << std::endl;
return 1;
}
std::cout << "Parsed: " << out << std::endl;
}
SirGuy changed the AST to suit the default synthesized attributes. At the cost of, indeed complicating the AST.
However, you could leverage attribute compatibity rules by adapting std::pair. In fact, that is as simple as including 1 header:
#include <boost/fusion/include/std_pair.hpp>
Then, everything compiles without change, printing:
Parsed: 3.4 a 5 b 6 c 7
I made the following changes:
#include <boost/fusion/tuple.hpp>
using second_type = std::vector<boost::fusion::tuple<char, int>>;
std::ostream& operator<<(std::ostream& os, second_type::value_type val)
{
return os << boost::fusion::get<0>(val) << ' ' << boost::fusion::get<1>(val);
}
and the result compiled for me. There are most certainly other solutions available too.
I am trying to use the letter character class from unicode i.e. \p{L} with Boost Spirit but I have no luck so far. Below is an example where I am trying to use (on line 30) the \p{L} character class. When I replace line 30 with line 29 it works but that is not the intended use as I need any letter from Unicode in my example.
My use case is for UTF8 only. At the end of they day what I am trying to do here is substract a unicode range from all unicode letters when using boost-spirit lexer.
PS
Of course, my example is trimmed down and may not make a lot of sense as a use case but I hope you get the idea.
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <iostream>
#include <fstream>
#include <chrono>
#include <vector>
using namespace boost;
using namespace boost::spirit;
using namespace std;
using namespace std::chrono;
std::vector<pair<string, string> > getTokenMacros() {
std::vector<pair<string, string> > tokenDefinitionsVector;
tokenDefinitionsVector.emplace_back("JAPANESE_HIRAGANA", "[\u3041-\u3096]");
tokenDefinitionsVector.emplace_back("JAPANESE_HIRAGANA1",
"[\u3099-\u309E]");
tokenDefinitionsVector.emplace_back("ASIAN_NWS", "{JAPANESE_HIRAGANA}|"
"{JAPANESE_HIRAGANA1}");
tokenDefinitionsVector.emplace_back("ASIAN_NWS_WORD", "{ASIAN_NWS}*");
//tokenDefinitionsVector.emplace_back("NON_ASIAN_LETTER", "[A-Za-z0-9]");
tokenDefinitionsVector.emplace_back("NON_ASIAN_LETTER", "[\\p{L}-[{ASIAN_NWS}]]");
tokenDefinitionsVector.emplace_back("WORD", "{NON_ASIAN_LETTER}+");
tokenDefinitionsVector.emplace_back("ANY", ".");
return tokenDefinitionsVector;
}
;
struct distance_func {
template<typename Iterator1, typename Iterator2>
struct result: boost::iterator_difference<Iterator1> {
};
template<typename Iterator1, typename Iterator2>
typename result<Iterator1, Iterator2>::type operator()(Iterator1& begin,
Iterator2& end) const {
return distance(begin, end);
}
};
boost::phoenix::function<distance_func> const distance_fctor = distance_func();
template<typename Lexer>
struct word_count_tokens: lex::lexer<Lexer> {
word_count_tokens() :
asianNwsWord("{ASIAN_NWS_WORD}", lex::min_token_id + 110), word(
"{WORD}", lex::min_token_id + 170), any("{ANY}",
lex::min_token_id + 3000) {
using lex::_start;
using lex::_end;
using boost::phoenix::ref;
std::vector<pair<string, string> > tokenMacros(getTokenMacros());
for (auto start = tokenMacros.begin(), end = tokenMacros.end();
start != end; start++) {
this->self.add_pattern(start->first, start->second);
}
this->self = asianNwsWord | word | any;
}
lex::token_def<> asianNwsWord, word, any;
};
int main(int argc, char* argv[]) {
typedef lex::lexertl::token<string::iterator> token_type;
typedef lex::lexertl::actor_lexer<token_type> lexer_type;
word_count_tokens<lexer_type> word_count_lexer;
// read in the file int memory
ifstream sampleFile("/home/dan/Documents/wikiSample.txt");
string str = "abc efg ぁあ";
string::iterator first = str.begin();
string::iterator last = str.end();
lexer_type::iterator_type iter = word_count_lexer.begin(first, last);
lexer_type::iterator_type end = word_count_lexer.end();
typedef boost::iterator_range<string::iterator> iterator_range;
vector<iterator_range> parsed_tokens;
while (iter != end && token_is_valid(*iter)) {
cout << (iter->id() - lex::min_token_id) << " " << iter->value()
<< endl;
const iterator_range range = get<iterator_range>(iter->value());
parsed_tokens.push_back(range);
++iter;
}
if (iter != end) {
string rest(first, last);
cout << endl << "!!!!!!!!!" << endl << "Lexical analysis failed\n"
<< "stopped at: \"" << rest << "\"" << endl;
cout << "#" << (int) rest.at(0) << "#" << endl;
}
return 0;
}
I have the example demo program with a boost::interprocess Containers of containers type.
But I like to use the class also a normal class within my process memory.
Can someone help me to write a constructor which takes no arguments to have the class initialized in my current process memory.
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <shmfw/serialization/interprocess_vector.hpp>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
using namespace boost::interprocess;
//Alias an STL-like allocator of ints that allocates ints from the segment
typedef allocator<int, managed_shared_memory::segment_manager> ShmemAllocator;
//Alias a vector that uses the previous STL-like allocator
typedef vector<int, ShmemAllocator> MyVector;
typedef allocator<void, managed_shared_memory::segment_manager > void_allocator;
class MyStruct {
public:
MyVector myVector;
//Since void_allocator is convertible to any other allocator<T>, we can simplify
//the initialization taking just one allocator for all inner containers.
MyStruct ( const void_allocator &void_alloc )
: myVector ( void_alloc )
{}
// Thats what I like to have
//MyStruct ()
// : myVector ( ?? )
//{}
};
int main () {
// I would like to have something like that working and also the shm stuff below
// MyStruct x;
managed_shared_memory segment;
//A managed shared memory where we can construct objects
//associated with a c-string
try {
segment = managed_shared_memory( create_only, "MySharedMemory", 65536 );
} catch (...){
segment = managed_shared_memory( open_only, "MySharedMemory" );
}
//Initialize the STL-like allocator
const ShmemAllocator alloc_inst ( segment.get_segment_manager() );
MyStruct *myStruct_src = segment.find_or_construct<MyStruct> ( "MyStruct" ) ( alloc_inst );
srand (time(NULL));
myStruct_src->myVector.push_back ( rand() );
MyStruct *myStruct_des = segment.find_or_construct<MyStruct> ( "MyStruct" ) ( alloc_inst );
for ( size_t i = 0; i < myStruct_src->myVector.size(); i++ ) {
std::cout << i << ": " << myStruct_src->myVector[i] << " = " << myStruct_des->myVector[i] << std::endl;
if(myStruct_src->myVector[i] != myStruct_des->myVector[i]) {
std::cout << "Something went wrong!" << std::endl;
}
}
//segment.destroy<MyVector> ( "MyVector" );
return 0;
}
If you change the allocator type, you change the container (such is the nature of compile-time template instantiation).
Technically, you could devise a type-erased allocator (à la std::function or boost::any_iterator) but this would probably result in abysmal performance. Also, it would still require all the allocators to correspond in all the statically known properties, reducing flexibility.
In reality, I suggest just templatizing MyStruct on the Allocator type to be used for any embedded containers. Then specifically take such an allocator in the constructor:
// Variant to use on the heap:
using HeapStruct = MyStruct<std::allocator>;
// Variant to use in shared memory:
using ShmemStruct = MyStruct<BoundShmemAllocator>;
Demo Program:
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <cassert>
namespace bip = boost::interprocess;
template <typename T>
using BoundShmemAllocator = bip::allocator<T, bip::managed_shared_memory::segment_manager>;
///////////////////////////////////////////////////////////////
// Your MyStruct, templatized for an Allocator class template
template <template<typename...> class Allocator>
class MyStruct {
public:
bip::vector<int, Allocator<int> > ints;
bip::vector<double, Allocator<double> > doubles;
MyStruct(const Allocator<void>& void_alloc = {})
: ints(void_alloc),
doubles(void_alloc)
{}
};
// Variant to use on the heap:
using HeapStruct = MyStruct<std::allocator>;
// Variant to use in shared memory:
using ShmemStruct = MyStruct<BoundShmemAllocator>;
//
///////////////////////////////////////////////////////////////
int main() {
srand(time(NULL));
// You can have something like this working:
HeapStruct x; // and also the shm stuff below
std::generate_n(std::back_inserter(x.ints), 20, &std::rand);
std::generate_n(std::back_inserter(x.doubles), 20, &std::rand);
// A managed shared memory where we can construct objects
bip::managed_shared_memory segment = bip::managed_shared_memory(bip::open_or_create, "MySharedMemory", 65536);
BoundShmemAllocator<int> const shmem_alloc(segment.get_segment_manager());
auto src = segment.find_or_construct<ShmemStruct>("MyStruct")(shmem_alloc);
src->ints.insert(src->ints.end(), x.ints.begin(), x.ints.end());
src->doubles.insert(src->doubles.end(), x.doubles.begin(), x.doubles.end());
auto des = segment.find_or_construct<ShmemStruct>("MyStruct")(shmem_alloc);
std::cout << "-------------------------";
boost::copy(src->ints, std::ostream_iterator<int>(std::cout << "\nsrc ints: ", "; "));
boost::copy(des->ints, std::ostream_iterator<int>(std::cout << "\ndes ints: ", "; "));
std::cout << "\n-------------------------";
boost::copy(src->doubles, std::ostream_iterator<double>(std::cout << "\nsrc doubles: ", "; "));
boost::copy(des->doubles, std::ostream_iterator<double>(std::cout << "\ndes doubles: ", "; "));
assert(src->ints.size() == des->ints.size());
assert(src->doubles.size() == des->doubles.size());
assert(boost::mismatch(src->ints, des->ints) == std::make_pair(src->ints.end(), des->ints.end()));
assert(boost::mismatch(src->doubles, des->doubles) == std::make_pair(src->doubles.end(), des->doubles.end()));
segment.destroy<ShmemStruct>("MyStruct");
}
I'm trying to set up a parser which, given a value, can assign it to a certain element of a vector, but I'm not entirely sure how to implement it.
Let's say the following piece of code parses the string (0){**+*+}. It should increment bar.a[0] once for every +, and bar.b[0] once for every *. The issue I'm encountering is that I'm not sure how to get a reference to a vector's element using _a:
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <vector>
//The struct containing the vector.
struct testStruct {
std::vector<int> a, b;
};
BOOST_FUSION_ADAPT_STRUCT (
testStruct,
(std::vector<int>, a)
(std::vector<int>, b)
)
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
namespace ascii = boost::spirit::ascii;
template<typename Iterator>
struct foo : qi::grammar<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> {
foo() : foo::base_type(start) {
using namespace qi::labels;
using qi::eps;
using qi::lit;
using qi::uint_;
using phoenix::at_c;
start = lit('(')
>> uint_ [_a = _1]
>> ')'
>> '{'
>> starsOrPlus(
at_c<_a>(at_c<0>(_val)), //This is where I'm not sure what to do.
at_c<_a>(at_c<1>(_val))
)
>> '}'
;
starsOrPlus = eps [_r1 = 0]
[_r2 = 0]
>> (
* (
(
+lit('+') [_r1 += 1]
)
^ (
+lit('*') [_r2 += 1]
)
)
)
;
}
qi::rule<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> start;
//Parses stars and pluses. Sets the first uint8_t to the number of *, and the
//second to the number of +.
qi::rule<Iterator, void(int&, int&), ascii::space_type> starsOrPlus;
};
//Main program
int main() {
std::string testString = "(2){**++*+}";
typedef foo<std::string::const_iterator> foo;
foo grammar;
testStruct bar;
std::string::const_iterator iter = testString.begin();
std::string::const_iterator end = testString.end();
bool parsed = phrase_parse(iter, end, grammar, ascii::space, bar);
if (parsed) {
//Do something with the data...
}
return 0;
}
This fails to compile with the following errors:
main.cpp||In constructor 'foo<Iterator>::foo()':|
main.cpp|36|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|36|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<0>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|
main.cpp|37|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|37|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<1>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|
So, clearly, I can't use a placeholder value within at_c. I'm also aware that, even if I could, there would also be the issue of re-sizing the vector if the given position is out of range.
How would I implement something like this? Am I just going about this entirely the wrong way?
This should get you started:
#include <vector>
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
struct testStruct
{
std::vector<int> a, b;
};
BOOST_FUSION_ADAPT_STRUCT
(
testStruct,
(std::vector<int>, a)
(std::vector<int>, b)
)
namespace bp = boost::phoenix;
namespace bs = boost::spirit;
namespace bsq = bs::qi;
template<typename Iterator>
struct foo : bsq::grammar<Iterator, testStruct(), bsq::locals<unsigned> >
{
foo() : foo::base_type(start)
{
using namespace bs::labels;
using bp::at_c;
using bp::resize;
using bs::lit;
using bs::uint_;
start
= '('
>> uint_
[
_a = _1,
resize(at_c<0>(_val), _1 + 1),
resize(at_c<1>(_val), _1 + 1)
]
>> "){"
>> starsOrPlus(at_c<0>(_val)[_a], at_c<1>(_val)[_a])
>> '}'
;
starsOrPlus
= *(
lit('+')[_r1 += 1]
| lit('*')[_r2 += 1]
)
;
}
bsq::rule<Iterator, testStruct(), bsq::locals<unsigned> > start;
bsq::rule<Iterator, void(int&, int&)> starsOrPlus;
};
void printvec(std::vector<int> const& vec)
{
bool first = true;
for (std::vector<int>::const_iterator it = vec.begin(), it_end = vec.end();
it != it_end;
++it)
{
if (first)
first = false;
else
std::cout << ", ";
std::cout << *it;
}
}
int main()
{
foo<std::string::const_iterator> grammar;
testStruct bar;
std::string const input = "(2){**++*}";
std::string::const_iterator first = input.begin(), last = input.end();
if (bsq::parse(first, last, grammar, bar) && first == last)
{
std::cout << "bar.a: ";
printvec(bar.a);
std::cout << "\nbar.b: ";
printvec(bar.b);
std::cout << '\n';
}
else
std::cout << "parse failed\n";
}
The notable changes here are:
The vectors inside of testStruct must be resized to a size sufficient for the desired index to be valid
operator[] is used instead of boost::phoenix::at_c to access the index of a vector, just as one would in "normal" code
Note that I took out the skip parser to simplify things (and because it didn't appear to be necessary); add it back if you need to -- it had no real relevance here.