Storing a boost::spirit::qi::rule in a std::list - boost

I have read the other thread about copy or reference semantics for boost::spirt::qi::rule. I am using Boost 1.42.
using boost::spirit::qi::phrase_parse;
typedef boost::spirit::qi::rule < std::string::const_iterator, boost::spirit::ascii::space_type > rule_type;
std::list < rule_type > ruleList;
std::string const s("abcdef");
std::string::const_iterator iter = s.begin(), end = s.end();
std::cout << typeid(char_).name() << std::endl;
ruleList.push_back(char_);
ruleList.push_back(*ruleList.back());
assert(phrase_parse(iter, s.end(), ruleList.back(), boost::spirit::ascii::space));
assert(iter == s.end());
This fails with...
Assertion `phrase_parse(iter, s.end(), ruleList.back(), traits::space())' failed.
Aborted (core dumped)
Is there a way to store rules in a STL list or deque? (References don't die until removed).

With Boost V1.45, this (essentially your code from above) works without problems (MSVC2010, g++ 4.5.1):
#include <list>
#include <string>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
using namespace boost::spirit;
int main()
{
typedef qi::rule<std::string::const_iterator, ascii::space_type> rule_type;
std::list<rule_type> ruleList;
std::string const s("abcdef");
std::string::const_iterator iter = s.begin(), end = s.end();
std::cout << typeid(qi::char_).name() << std::endl;
ruleList.push_back(qi::char_);
ruleList.push_back(*ruleList.back());
assert(qi::phrase_parse(iter, s.end(), ruleList.back(), ascii::space));
assert(iter == s.end());
return 0;
}
Therefore, I assume it's a bug in the version of Spirit you're using.

I could not get your example to compile. Aside from not using the correct types from ...::qi, you added a () to the trait::space type.
This works w/o problem for me (boost 1.44)
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <vector>
#include <cassert>
using boost::spirit::qi::phrase_parse;
typedef boost::spirit::qi::rule < std::string::const_iterator, boost::spirit::qi::space_type > rule_type;
int main() {
std::list < rule_type > ruleList;
std::string const s("abcdef");
std::string::const_iterator iter = s.begin(), end = s.end();
ruleList.push_back(*boost::spirit::qi::char_);
assert(phrase_parse(iter, s.end(), ruleList.back(), boost::spirit::qi::space));
assert(iter == s.end());
}
~>g++ test.cpp && ./a.out
~>
please note I use qi::space_type and `qi::space instead of the ascii namespace. I have no idea what/where the trait namespace is.

Related

serialize temporary into boost archive

The following is not possible for any boost output archive:
int foo(){
return 4;
}
ar << static_cast<unsigned int>(foo());
Is there an alternative without out creating a local temporary x=foo().
and why is the underlying archive operator <<(T & t) not const reference , for an output archive such that the above would work?
This seems to work, and I think this is why:
... To help detect such cases, output archive operators expect to be
passed const reference arguments.
It seems worth noting that in your example ar << foo(); does not work either (i.e. it doesn't have to do with your cast).
#include <fstream>
#include <iostream>
#include <boost/serialization/serialization.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
unsigned int foo(){
return 4;
}
int main()
{
{
std::ofstream outputStream("someFile.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << static_cast<const int&>(foo());
}
std::ifstream inputStream("someFile.txt");
boost::archive::text_iarchive inputArchive(inputStream);
int readBack;
inputArchive >> readBack;
std::cout << "Read back: " << readBack << std::endl;
return 0;
}

Compilation issue with boost range copy of filesystem path

The following code fails to compile with 1.58 while it was compiling with 1.46. I guess it's a type conversion issue, but I can't make it right.
my code
#include <boost/filesystem.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <vector>
using namespace boost;
using namespace filesystem;
using namespace adaptors;
int main(int argc, char ** argv)
{
recursive_directory_iterator beg = recursive_directory_iterator(".");
recursive_directory_iterator end = recursive_directory_iterator();
iterator_range<recursive_directory_iterator> files =
make_iterator_range(beg, end);
std::function<bool (path const & path)> fileFilter =
[](path const & path) -> bool {
return is_regular_file(path);
};
std::vector<path> paths;
copy(files | filtered(fileFilter), std::back_inserter(paths));
// works:
//copy(files, std::back_inserter(paths));
// also works:
//for(recursive_directory_iterator it = beg; it != end; ++it){
// if(fileFilter(*it)){
// paths.push_back(*it);
// }
//}
}
Error message (VS2010)
Error 1 error C2664:
'boost::filesystem::recursive_directory_iterator::recursive_directory_iterator(const
boost::filesystem::path
&,boost::filesystem::symlink_option::enum_type)' : cannot convert
parameter 1 from
'boost::iterators::detail::postfix_increment_proxy' to
'const boost::filesystem::path
&' [...]\boost\1.58.0_32\include\boost-1_58\boost\range\concepts.hpp 201 1 [...]
Can anyone help ?
Edit
Filed as https://svn.boost.org/trac/boost/ticket/11228.
This seems to be a bug introduced somewhere since Boost 1.55. Using boost 1.55 this compiles ok.
It could be this bug: https://svn.boost.org/trac/boost/ticket/10989
boost_1_57_0/boost/concept_check.hpp|210 col 13| error: conversion from ‘boost::iterators::single_pass_traversal_tag’ to non-scalar type ‘boost::iterators::forward_traversal_tag’ requested
The filtered adaptor requires the input to be forward_traversal tag. But recursive_directory_iterator only promises single_pass_traversal tag:
BOOST_RANGE_CONCEPT_ASSERT((
Convertible<
BOOST_DEDUCED_TYPENAME ForwardIteratorConcept::traversal_category,
forward_traversal_tag
>));
WORKAROUND
You can disable concept checks for now: -DBOOST_RANGE_ENABLE_CONCEPT_ASSERT=0:
Live On Coliru
#include <boost/filesystem.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <vector>
#include <iostream>
namespace fs = boost::filesystem;
using namespace boost::adaptors;
int main() {
fs::recursive_directory_iterator beg("."), end;
auto fileFilter = [](fs::path const & path) { return is_regular_file(path); };
std::vector<fs::path> paths;
copy(boost::make_iterator_range(beg, end) | filtered(fileFilter), std::back_inserter(paths));
for(auto& p : paths)
std::cout << p << "\n";
}
Prints
"./main.cpp"
"./a.out"

Move or swap a stringstream

I want to move a stringstream, in the real world application I have some stringstream class data member, which I want to reuse for different string's during operation.
stringstream does not have a copy-assignment or copy constructor, which makes sense. However, according to cppreference.com and cplusplus.com std::stringstream should have a move assignment and swap operation defined. I tried both, and both fail.
Move assignment
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream stream("1234");
//stream = std::move(std::stringstream("5678"));
stream.operator=(std::move(std::stringstream("5678")));
//stream.operator=(std::stringstream("5678"));
return 0;
}
source: http://ideone.com/Izyanb
prog.cpp:11:56: error: use of deleted function ‘std::basic_stringstream<char>& std::basic_stringstream<char>::operator=(const std::basic_stringstream<char>&)’
stream.operator=(std::move(std::stringstream("5678")));
The compiler states that there is no copy assignment for all three statements, which is true. However, I fail to see why it is not using the move-assignment, especially since std::move is supposed to return a rvalue reference. Stringstream should have a move assignment, as shown here: http://en.cppreference.com/w/cpp/io/basic_stringstream/operator%3D
PS: I'm working with c++11, hence rvalue-references are part of the 'world'.
Swap
This I found really strange, I copied example code from cplusplus.com and it failed:
// swapping stringstream objects
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream foo;
std::stringstream bar;
foo << 100;
bar << 200;
foo.swap(bar);
int val;
foo >> val; std::cout << "foo: " << val << '\n';
bar >> val; std::cout << "bar: " << val << '\n';
return 0;
}
source: http://ideone.com/NI0xMS
cplusplus.com source: http://www.cplusplus.com/reference/sstream/stringstream/swap/
prog.cpp: In function ‘int main()’:
prog.cpp:14:7: error: ‘std::stringstream’ has no member named ‘swap’
foo.swap(bar);
What am I missing? Why can't I move or swap a stringstream? How should I swap or move a stringstream?
This is a missing feature on GCC : see bug 54316 , it has been fixed (you can thank Jonathan Wakely) for the next versions (gcc 5)
Clang with libc++ compiles this code :
int main () {
std::stringstream stream("1234");
std::stringstream stream2 = std::move(std::stringstream("5678"));
return 0;
}
Live demo
And it also compiles the example with std::stringstream::swap
I have an alternative to moving or swapping, one can also clear and set a stringstream to a new string:
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream ss("1234");
ss.clear();
ss.str("5678");
int val;
ss >> val; std::cout << "val: " << val << '\n';
return 0;
}
It's a clean work around that does not require one to refactor code, except for the localized section where the swap is changed to a clear() and str().

Why won't this program work in release mode?

#include <iostream>
#include <fstream>
#include <stdlib.h> // includes the "atoi" function
#include <string>
using namespace std;
#include <sstream>;
int main()
{
std::fstream f;
f.open("file.in", std::fstream::in);
// read data
int count = 0;
std::string line = "";
getline( f, line, '\n' );
count = atoi( line.c_str() );
f.close();
f.open("file.in", std::fstream::out | std::fstream::trunc);
// write data
++count;
f << count << endl;
f.close();
return 0;
}
This works in debug mode in Visual Studio but when I run it as an application it doesn't work. I've initialized all variables so I'm not sure what else to check.
This line
f.open("file.in", std::fstream::in);
Make sure file.in is in \bin\release
I also advice your to use try/catch statements and print your errors

stringstream manipulators & vstudio 2003

I am trying to use a stringstream object in VC++ (VStudio 2003) butI am getting an error when I use the overloaded << operator to try and set some manipulators.
I am trying the following:
int SomeInt = 1;
stringstream StrStream;
StrStream << std::setw(2) << SomeInt;
This will not compile (error C2593: 'operator <<' is ambiguous).
Does VStudio 2003 support using manipulators in this way?
I know that I can just set the width directly on the stringstream object e.g. StrStream.width(2);
I was wondering why the more usual method doesn't work?
Are you sure you included all of the right headers? The following compiles for me in VS2003:
#include <iostream>
#include <sstream>
#include <iomanip>
int main()
{
int SomeInt = 1;
std::stringstream StrStream;
StrStream << std::setw(2) << SomeInt;
return 0;
}
I love this reference site for stream questions like this.
/Allan
You probably just forgot to include iomanip, but I can't be sure because you didn't include code for a complete program there.
This complete program works fine over here using VS 2003:
#include <sstream>
#include <iomanip>
int main()
{
int SomeInt = 1;
std::stringstream StrStream;
StrStream << std::setw(2) << SomeInt;
}

Resources