I'm updating some old code which worked under older (~1.38 or so) versions of boost. I've updated to boost 1.63 and can not seem to figure out how to get the old version to compile.
This is the relevant parts
void print (StateStruct const& ss)
{
std::cout << ss.Name;
}
struct StateStruct
{
std::string Name;
float avalue;
}
BOOST_FUSION_ADAPT_STRUCT (
StateStruct,
(std::string, NAME)
(float, avalue)
)
and the parser rule that used to work
state %=
( qi::lexeme[qi::char_(a-zA-Z) >> +qi::char("-a-zA-Z0-9_")]
>> qi::float_
)
[phoenix::bind(&print, qi::_val)]
;
qi::rule (Iterator, StateStruct(), skipper_type) state;
With g++ 6.3.0 and boost 1.63 I get and error message along the lines of
invalid initialization of type const StateStruct::StateStruct& from expression of type boost::fusion::vector<boost::fusion::vector<char, std::vector<char, std::allocator<char> > >, float>
without the semantic action the code compiles and debugging the state rule shows the expected results. What do I need to do to correctly initialize the struct?
I agree this looks like a regression, you may want to report it to the maintainers at the [spirit-general] mailing list.
On a hunch I remembered an obscure define that got introduced as some kind of a compatibility hack¹. Lo and behold, the thing compiles with BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT defined:
Live On Coliru:
#define BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
struct StateStruct { std::string Name; float avalue; };
BOOST_FUSION_ADAPT_STRUCT(StateStruct, Name, avalue)
void print(StateStruct const& ss) { std::cout << "print: " << ss.Name << "\n"; }
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
int main() {
using Iterator = std::string::const_iterator;
using skipper_type = qi::space_type;
qi::rule<Iterator, StateStruct(), skipper_type> state;
state %=
( qi::as_string [ qi::lexeme[qi::char_("a-zA-Z") >> +qi::char_("-a-zA-Z0-9_")] ] >> qi::float_
)
[ px::bind(&print, qi::_val) ]
;
std::string const input("identifier31415 3.1415");
Iterator f = input.begin(), l = input.end();
StateStruct parsed;
bool ok = qi::phrase_parse(f, l, state, qi::space, parsed);
if (ok)
std::cout << "Parsed: " << boost::fusion::as_vector(parsed) << "\n";
else
std::cout << "Parse failed\n";
if (f != l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}
Printing:
print: identifier31415
Parsed: (identifier31415 3.1415)
¹ (I think it got introduced to give some people a feature that could not be generally enabled because it would break existing code)
Related
I was toying with Boost.Spirit X3 calculator example when I encountered an error I couldn't get my head around.
I minimized the program to reduce complexity still throwing the same error.
Say I want to parse an input as a list of statements (strings) followed by a delimiter (';').
This is my structure:
namespace client { namespace ast
{
struct program
{
std::list<std::string> stmts;
};
}}
BOOST_FUSION_ADAPT_STRUCT(client::ast::program,
(std::list<std::string>, stmts)
)
The grammar is as follows:
namespace client
{
namespace grammar
{
x3::rule<class program, ast::program> const program("program");
auto const program_def =
*((*char_) > ';')
;
BOOST_SPIRIT_DEFINE(
program
);
auto calculator = program;
}
using grammar::calculator;
}
Invoked
int
main()
{
std::cout <<"///////////////////////////////////////////\n\n";
std::cout << "Expression parser...\n\n";
std::cout << //////////////////////////////////////////////////\n\n";
std::cout << "Type an expression...or [q or Q] to quit\n\n";
typedef std::string::const_iterator iterator_type;
typedef client::ast::program ast_program;
std::string str;
while (std::getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
auto& calc = client::calculator; // Our grammar
ast_program program; // Our program (AST)
iterator_type iter = str.begin();
iterator_type end = str.end();
boost::spirit::x3::ascii::space_type space;
bool r = phrase_parse(iter, end, calc, space, program);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout<< '\n';
std::cout << "-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
Error I get is
/opt/boost_1_66_0/boost/spirit/home/x3/support/traits/container_traits.hpp: In instantiation of ‘struct boost::spirit::x3::traits::container_value<client::ast::program, void>’:
.
.
.
/opt/boost_1_66_0/boost/spirit/home/x3/support/traits/container_traits.hpp:76:12: error: no type named ‘value_type’ in ‘struct client::ast::program’
struct container_value
/opt/boost_1_66_0/boost/spirit/home/x3/operator/detail/sequence.hpp:497:72: error: no type named ‘type’ in ‘struct boost::spirit::x3::traits::container_value<client::ast::program, void>’
, typename traits::is_substitute<attribute_type, value_type>::type());
^~~~~~
Things I tried:
Following Getting boost::spirit::qi to use stl containers
Even though it uses Qi I nonetheless tried:
namespace boost{namespace spirit{ namespace traits{
template<>
struct container_value<client::ast::program>
//also with struct container<client::ast::program, void>
{
typedef std::list<std::string> type;
};
}}}
You see I'm kinda in the dark, so expectably to no avail.
parser2.cpp:41:8: error: ‘container_value’ is not a class template
struct container_value<client::ast::program>
^~~~~~~~~~~~~~~
In the same SO question I author says "There is one known limitation though, when you try to use a struct that has a single element that is also a container compilation fails unless you add qi::eps >> ... to your rule."
I did try adding a dummy eps also without success.
Please, help me decipher what that error means.
Yup. This looks like another limitation with automatic propagation of attributes when single-element sequences are involved.
I'd probably bite the bullet and change the rule definition from what it is (and what you'd expect to work) to:
x3::rule<class program_, std::vector<std::string> >
That removes the root of the confusion.
Other notes:
you had char_ which also eats ';' so the grammar would never succeed because no ';' would follow a "statement".
your statements aren't lexeme, so whitespace is discarded (is this what you meant? See Boost spirit skipper issues)
your statement could be empty, which meant parsing would ALWAYS fail at the end of input (where it would always read an empty state, and then discover that the expected ';' was missing). Fix it by requiring at least 1 character before accepting a statement.
With some simplifications/style changes:
Live On Coliru
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <list>
namespace x3 = boost::spirit::x3;
namespace ast {
using statement = std::string;
struct program {
std::list<statement> stmts;
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::program, stmts)
namespace grammar {
auto statement
= x3::rule<class statement_, ast::statement> {"statement"}
= +~x3::char_(';');
auto program
= x3::rule<class program_, std::list<ast::statement> > {"program"}
= *(statement >> ';');
}
#include <iostream>
#include <iomanip>
int main() {
std::cout << "Type an expression...or [q or Q] to quit\n\n";
using It = std::string::const_iterator;
for (std::string str; std::getline(std::cin, str);) {
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
auto &parser = grammar::program;
ast::program program; // Our program (AST)
It iter = str.begin(), end = str.end();
if (phrase_parse(iter, end, parser, x3::space, program)) {
std::cout << "Parsing succeeded\n";
for (auto& s : program.stmts) {
std::cout << "Statement: " << std::quoted(s, '\'') << "\n";
}
}
else
std::cout << "Parsing failed\n";
if (iter != end)
std::cout << "Remaining unparsed: " << std::quoted(std::string(iter, end), '\'') << "\n";
}
}
Which for input "a;b;c;d;" prints:
Parsing succeeded
Statement: 'a'
Statement: 'b'
Statement: 'c'
Statement: 'd'
I'm trying to create a GPIB parser using Spirit.Qi. Sometimes the response can
be either an error or a normal response. This seemed like a good use case for
the alternative parser which yields a boost::variant; however, if one of the
variant types contains a string the code fails to compile. Here is a simplified
version that reproduces the error.
struct C1 {
std::string h{""};
int i{0};
};
BOOST_FUSION_ADAPT_STRUCT(C1, (std::string, h)(int, i))
struct C2 {
std::string h{""};
std::string c{};
};
BOOST_FUSION_ADAPT_STRUCT(C2, (std::string, h)(std::string, c))
using VariantType = boost::variant<C1, C2>;
int main() {
std::string s2{"C2:Zoo3"};
VariantType v1;
if(qi::parse(s1.begin(), s1.end(),
(qi::string("C1") >> ":" >> qi::int_) |
(qi::string("C2") >> ":" >> *qi::char_),
v1)) {
if(boost::get<C1>(&v1)) {
auto a1 = boost::get<C1>(v1);
std::cout << "Parsing Succeeded, a1 = " << a1.h << ":"
<< a1.i << std::endl;
}
else {
auto a2 = boost::get<C2>(v1);
std::cout << "Parsing Succeeded, a2 = " << a2.h << ":"
<< a2.c << std::endl;
}
}
else {
std::cout << "Parsing Failed" << std::endl;
}
return 0;
}
I've experimented with various parsers other than *qi::char_ (eg. qi::string) to no avail. If I change C2::c to a char it works ok for 1 char. The best workaround I have found so far is to change C2::c to a std::vector<char>, this works fine but isn't ideal. I also tried telling Qi that std::string is a container like here. But qi knows what a std::string is so I'm pretty sure it ignores my customization. I think this is all because std::string isn't a POD and wasn't supported in unions until the rules were relaxed, but it works with boost::variant when it isn't in a struct, and std::vector works. Any ideas/workarounds would be appreciated.
*Note: I didn't post the compiler errors as they are long and mangled and I figured this was a known issue of std::string and variants. If they would be helpful let me know and I'll post them.
There's nothing wrong with the code, as far as I can tell.
I've tested on c++1{1,4,y} and boost 1.{57,58}.0, using gcc {4.9,5.x} and clang++ 3.5.
I suspect you may have an awkward Boost verion. Try using qi::as_string[*qi::char_] there. ¹
Live On Coliru
#include <iostream>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
struct C1 {
std::string h{""};
int i{0};
friend std::ostream& operator<<(std::ostream& os, C1 const& c1) {
return os << "C1 {h:'" << c1.h << "', i:'" << c1.i << "'}";
}
};
struct C2 {
std::string h{""};
std::string c{};
friend std::ostream& operator<<(std::ostream& os, C2 const& c2) {
return os << "C2 {h:'" << c2.h << "', c:'" << c2.c << "'}";
}
};
BOOST_FUSION_ADAPT_STRUCT(C1, (std::string, h)(int, i))
BOOST_FUSION_ADAPT_STRUCT(C2, (std::string, h)(std::string, c))
using VariantType = boost::variant<C1, C2>;
namespace qi = boost::spirit::qi;
int main() {
VariantType value;
for(std::string s1 : {
"C2:Zoo3",
"C1:1234"
})
{
if(qi::parse(s1.begin(), s1.end(),
(qi::string("C1") >> ":" >> qi::int_) |
(qi::string("C2") >> ":" >> *qi::char_),
value))
std::cout << "Parsing Succeeded: " << value << "\n";
else
std::cout << "Parsing Failed" << std::endl;
}
}
Prints
Parsing Succeeded: C2 {h:'C2', c:'Zoo3'}
Parsing Succeeded: C1 {h:'C1', i:'1234'}
¹ I don't recommend qi::attr_cast<> as I remember this having had an awkward bug in awkwardly old boost versions.
In my Boost Spirit grammar I would like to have a rule that does this:
rule<...> noCaseLit = no_case[ lit( "KEYWORD" ) ];
but for a custom keyword so that I can do this:
... >> noCaseLit( "SomeSpecialKeyword" ) >> ... >> noCaseLit( "OtherSpecialKeyword1" )
Is this possible with Boost Spirit rules and if so how?
P.S. I use the case insensitive thing as an example, what I'm after is rule parameterization in general.
Edits:
Through the link provided by 'sehe' in the comments I was able to come close to what I wanted but I'm not quite there yet.
/* Defining the noCaseLit rule */
rule<Iterator, string(string)> noCaseLit = no_case[lit(_r1)];
/* Using the noCaseLit rule */
rule<...> someRule = ... >> noCaseLit(phx::val("SomeSpecialKeyword")) >> ...
I haven't yet figured out a way to automatically convert the literal string to the Phoenix value so that I can use the rule like this:
rule<...> someRule = ... >> noCaseLit("SomeSpecialKeyword") >> ...
The easiest way is to simply create a function that returns your rule/parser. In the example near the end of this page you can find a way to declare the return value of your function. (The same here in a commented example).
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
namespace ascii = boost::spirit::ascii;
namespace qi = boost::spirit::qi;
typedef boost::proto::result_of::deep_copy<
BOOST_TYPEOF(ascii::no_case[qi::lit(std::string())])
>::type nocaselit_return_type;
nocaselit_return_type nocaselit(const std::string& keyword)
{
return boost::proto::deep_copy(ascii::no_case[qi::lit(keyword)]);
}
//C++11 VERSION EASIER TO MODIFY (AND DOESN'T REQUIRE THE TYPEDEF)
//auto nocaselit(const std::string& keyword) -> decltype(boost::proto::deep_copy(ascii::no_case[qi::lit(keyword)]))
//{
// return boost::proto::deep_copy(ascii::no_case[qi::lit(keyword)]);
//}
int main()
{
std::string test1="MyKeYWoRD";
std::string::const_iterator iter=test1.begin();
std::string::const_iterator end=test1.end();
if(qi::parse(iter,end,nocaselit("mYkEywOrd"))&& (iter==end))
std::cout << "Parse 1 Successful" << std::endl;
else
std::cout << "Parse 2 Failed. Remaining: " << std::string(iter,end) << std::endl;
qi::rule<std::string::const_iterator,ascii::space_type> myrule =
*(
( nocaselit("double") >> ':' >> qi::double_ )
| ( nocaselit("keyword") >> '-' >> *(qi::char_ - '.') >> '.')
);
std::string test2=" DOUBLE : 3.5 KEYWORD-whatever.Double :2.5";
iter=test2.begin();
end=test2.end();
if(qi::phrase_parse(iter,end,myrule,ascii::space)&& (iter==end))
std::cout << "Parse 2 Successful" << std::endl;
else
std::cout << "Parse 2 Failed. Remaining: " << std::string(iter,end) << std::endl;
return 0;
}
I'm a newbie in boost::spirit. I wrote the program to parse a SQL statement, like "select * from table where conditions". It compile failed. A large of template errors reported. So, would somebody help me?
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct db_select {
void exec() {}
std::string filed;
std::string table;
std::string condition;
};
std::ostream& operator<<(std::ostream& os, const db_select& se) {
return os << "filed: " << se.filed << " table: " << se.table << " condition: " << se.condition;
}
template <class Iterator>
struct selecter : qi::grammar<Iterator, db_select (), ascii::space_type> {
selecter() : selecter::base_type(se) {
se %= "select" >> +qi::char_ << "from" << +qi::char_ << "where" << +qi::char_;
}
qi::rule<Iterator, db_select (), ascii::space_type> se;
};
int main(int argc, char* argv[]) {
if (argc < 2)
return -1;
std::string str(argv[1]);
const char* first = str.c_str();
const char* last = &str[str.size()];
selecter<const char*> se;
db_select rst;
bool r = qi::phrase_parse(first, last, se, ascii::space, rst);
if (!r || first != last) {
std::cout << "parse failed, at: " << std::string(first, last) << std::endl;
return -1;
} else
std::cout << "success, " << rst << std::endl;
return 0;
}
Edit Finally behind a computer, revised answer:
There were three things to note
1. Syntax errors
The parser expression contained errors (<< instead of >> as intended). This accounts for a lot of compile errors. Note the appearance of ******* in the compiler error:
/.../qi/nonterminal/rule.hpp|176 col 13| error: no matching function for call to ‘assertion_failed(mpl_::failed************
which is designed to lead you to the corresponding comment in the source code:
// Report invalid expression error as early as possible.
// If you got an error_invalid_expression error message here,
// then the expression (expr) is not a valid spirit qi expression.
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
Easily fixed. One down, two to go!
2. Adapting the struct
In order to assign to your datatype as an rule attribute, you need to make it fusion compatible. The most convenient way:
BOOST_FUSION_ADAPT_STRUCT(db_select,
(std::string,field)(std::string,table)(std::string,condition));
Now the code compiles. But the parsing fails. One more to go:
3. Lexemes
Further more you will need to take measures to avoid 'eating' your query keywords with the +qi::char_ expressions.
As a basis, consider writing it something like
lexeme [ (!lit("where") >> +qi::graph) % +qi::space ]
lexeme inhibits the skipper for the enclosed expression
! Asserts that the specified keyword must not match
Lastly, look at the docs for qi::no_case to do case-insensitive matching.
FULL CODE
#include <iostream>
#include <string>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct db_select {
void exec() {}
std::string field;
std::string table;
std::string condition;
};
BOOST_FUSION_ADAPT_STRUCT(db_select,(std::string,field)(std::string,table)(std::string,condition));
std::ostream& operator<<(std::ostream& os, const db_select& se) {
return os << "field: " << se.field << " table: " << se.table << " condition: " << se.condition;
}
template <class Iterator>
struct selecter : qi::grammar<Iterator, db_select (), qi::space_type> {
selecter() : selecter::base_type(se) {
using namespace qi;
se %= "select"
>> lexeme [ (!lit("from") >> +graph) % +space ] >> "from"
>> lexeme [ (!lit("where") >> +graph) % +space ] >> "where"
>> +qi::char_;
}
qi::rule<Iterator, db_select (), qi::space_type> se;
};
int main(int argc, char* argv[]) {
if (argc < 2)
return -1;
std::string str(argv[1]);
const char* first = str.c_str();
const char* last = &str[str.size()];
selecter<const char*> se;
db_select rst;
bool r = qi::phrase_parse(first, last, se, qi::space, rst);
if (!r || first != last) {
std::cout << "parse failed, at: " << std::string(first, last) << std::endl;
return -1;
} else
std::cout << "success, " << rst << std::endl;
return 0;
}
Test:
g++ test.cpp -o test
./test "select aap, noot, mies from table where field = 'value'"
Output:
success, field: aap,noot,mies table: table condition: field='value'
I'm parsing a text file, possibly several GB in size, consisting of lines as follows:
11 0.1
14 0.78
532 -3.5
Basically, one int and one float per line. The ints should be ordered and non-negative. I'd like to verify the data are as described, and have returned to me the min and max int in the range. This is what I've come up with:
#include <iostream>
#include <string>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace px = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace my_parsers
{
using namespace qi;
using px::at_c;
using px::val;
template <typename Iterator>
struct verify_data : grammar<Iterator, locals<int>, std::pair<int, int>()>
{
verify_data() : verify_data::base_type(section)
{
section
= line(val(0)) [ at_c<0>(_val) = _1]
>> +line(_a) [ _a = _1]
>> eps [ at_c<1>(_val) = _a]
;
line
%= (int_ >> other) [
if_(_r1 >= _1)
[
std::cout << _r1 << " and "
<< _1 << val(" out of order\n")
]
]
;
other
= omit[(lit(' ') | '\t') >> float_ >> eol];
}
rule<Iterator, locals<int>, std::pair<int, int>() > section;
rule<Iterator, int(int)> line;
rule<Iterator> other;
};
}
using namespace std;
int main(int argc, char** argv)
{
string input("11 0.1\n"
"14 0.78\n"
"532 -3.6\n");
my_parsers::verify_data<string::iterator> verifier;
pair<int, int> p;
std::string::iterator begin(input.begin()), end(input.end());
cout << "parse result: " << boolalpha
<< qi::parse(begin, end, verifier, p) << endl;
cout << "p.first: " << p.first << "\np.second: " << p.second << endl;
return 0;
}
What I'd like to know is the following:
Is there a better way of going about this? I have used inherited and synthesised attributes, local variables and a bit of phoenix voodoo. This is great; learning the tools is good but I can't help thinking there might be a much simpler way of achieving the same thing :/ (within a PEG parser that is...)
How could it be done without the local variable for instance?
More info: I have other data formats that are being parsed at the same time and so I'd like to keep the return value as a parser attribute. At the moment this is a std::pair, the other data formats when parsed, will expose their own std::pairs for instance and it's these that I'd like to stuff in a std::vector.
This is at least a lot shorter already:
down to 28 LOC
no more locals
no more fusion vector at<> wizardry
no more inherited attributes
no more grammar class
no more manual iteration
using expectation points (see other) to enhance parse error reporting
this parser expressions synthesizes neatly into a vector<int> if you choose to assign it with %= (but it will cost performance, besides potentially allocating a largish array)
.
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
namespace px = boost::phoenix;
namespace qi = boost::spirit::qi;
typedef std::string::iterator It;
int main(int argc, char** argv)
{
std::string input("11 0.1\n"
"14 0.78\n"
"532 -3.6\n");
int min=-1, max=0;
{
using namespace qi;
using px::val;
using px::ref;
It begin(input.begin()), end(input.end());
rule<It> index = int_
[
if_(ref(max) < _1) [ ref(max) = _1 ] .else_ [ std::cout << _1 << val(" out of order\n") ],
if_(ref(min) < 0) [ ref(min) = _1 ]
] ;
rule<It> other = char_(" \t") > float_ > eol;
std::cout << "parse result: " << std::boolalpha
<< qi::parse(begin, end, index % other) << std::endl;
}
std::cout << "min: " << min << "\nmax: " << max << std::endl;
return 0;
}
Bonus
I might suggest taking the validation out of the expression and make it a free-standing function; of course, this makes things more verbose (and... legible) and my braindead sample uses global variables... -- but I trust you know how to use boost::bind or px::bind to make it more real-life
In addition to the above
down to 27 LOC even with the free function
no more phoenix, no more phoenix includes (yay compile times)
no more phoenix expression types in debug builds ballooning the binary and slowing it down
no more var, ref, if_, .else_ and the wretched operator, (which had major bug risk (at some time) due to the overload not being included with phoenix.hpp)
(easily ported to c++0x lambda's - immediately removing the need for global variables)
.
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
namespace px = boost::phoenix;
namespace qi = boost::spirit::qi;
typedef std::string::iterator It;
int min=-1, max=0, linenumber=0;
void validate_index(int index)
{
linenumber++;
if (min < 0) min = index;
if (max < index) max = index;
else std::cout << index << " out of order at line " << linenumber << std::endl;
}
int main(int argc, char** argv)
{
std::string input("11 0.1\n"
"14 0.78\n"
"532 -3.6\n");
It begin(input.begin()), end(input.end());
{
using namespace qi;
rule<It> index = int_ [ validate_index ] ;
rule<It> other = char_(" \t") > float_ > eol;
std::cout << "parse result: " << std::boolalpha
<< qi::parse(begin, end, index % other) << std::endl;
}
std::cout << "min: " << min << "\nmax: " << max << std::endl;
return 0;
}
I guess a much simpler way would be to parse the file using standard stream operations and then check the ordering in a loop. First, the input:
typedef std::pair<int, float> value_pair;
bool greater(const value_pair & left, const value_pair & right) {
return left.first > right.first;
}
std::istream & operator>>(std::istream & stream, value_pair & value) {
stream >> value.first >> value.second;
return stream;
}
The use it like this:
std::ifstream file("your_file.txt");
std::istream_iterator<value_pair> it(file);
std::istream_iterator<value_pair> eof;
if(std::adjacent_find(it, eof, greater) != eof) {
std::cout << "The values are not ordered" << std::endl;
}
I find this a lot simpler.