I am using boost spirit qi to parse inbound data then dispatch the correct functionality depending on it's content.
I am using boost::signals to manage the callbacks; my problem is that I don't seem to be able to use phoenix bind with the boost signals.
Consider the following test case:
#include <boost/signals.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <iostream>
void f(int i) {
std::cout << i << '\n';
}
int main() {
boost::signal<void(int)> sig;
sig.connect(f);
std::string s="123";
auto first=s.cbegin(), last=s.cend();
boost::spirit::qi::parse(
first, last,
(
boost::spirit::qi::int_
[
boost::phoenix::bind(sig, boost::spirit::qi::_1)
]
)
);
}
This doesn't compile, spitting out a wall of errors.
Note that if I replace the phoenix bind line with
boost::phoenix::bind(&f, boost::spirit::qi::_1)
it works as expected (however due to the larger design of the program this isn't possible).
Thanks in advance.
As noted by Igor R. in the comments, your original error was due to the fact that phoenix::bind copies its arguments by default and boost::signals are non-copyable. When you use phoenix::ref to solve that, another error emerges, this one caused by Boost.Phoenix v2's inability to find the returned type. This can also be easily solved by defining BOOST_SPIRIT_USE_PHOENIX_V3.
#include <boost/signals.hpp>
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <iostream>
void f(int i) {
std::cout << i << '\n';
}
int main() {
boost::signal<void(int)> sig;
sig.connect(f);
std::string s="123";
auto first=s.cbegin(), last=s.cend();
boost::spirit::qi::parse(
first, last,
(
boost::spirit::qi::int_
[
boost::phoenix::bind(boost::phoenix::ref(sig), boost::spirit::qi::_1)
]
)
);
}
Related
So in my code, I've used a method is_empty()in the boost library. I know is_empty has two definitions, one is in the filesystem library of boost:
std::filesystem:is_empty(const std::filesystem::path& p).
And another is in std::integral_constant:
inline constexpr bool is_empty_v = is_empty<T>::value;
I intended to use the one that is in the boost library, but how can I do it? I tried to not do using namespace std at the beginning. Instead, every time I need to cout, I'd use std::cout to avoid the possible ambiguous on my is_empty method. But I still got the same error if I do this. Is there any other way that can resolve this misconception? I attached part of my code snippet below. Thank you!
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "boost/filesystem.hpp"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
...
using namespace boost::filesystem;
using namespace cv;
... inside main() function:
...
directory_iterator itr(param.referFolder);
if( is_empty(itr->path()) )
{
std::cout << "ERROR: ReferenceFolder is empty. Please place reference images inside." << std::endl;
return 1;
}
... ...
for(directory_iterator itr(param.dataFolder); itr != end_itr; ++itr) // search every folder
{
if(is_directory(itr->status()) && !is_empty(itr->path())){
... ...
}
}
I have recently installed boost, and i was experimenting with the Spirit library. I compiled a simple example which parses a comma-seperated list of numbers and adds them together. The program compiled, but my compiler (VS 2013) issued a rediculous amount of warnings. Have a look at the source:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
using qi::double_;
using qi::_1;
using ascii::space;
using phoenix::ref;
template <typename Iterator>
bool adder(Iterator first, Iterator last, double& n)
{
bool r = qi::phrase_parse(first, last,
// Begin grammar
(
double_[ref(n) = _1] >> *(',' >> double_[ref(n) += _1])
)
,
// End grammar
space);
if (first != last) // fail if we did not get a full match
return false;
return r;
}
int main()
{
std::string str;
std::getline(std::cin, str);
double result;
if (!adder(str.begin(), str.end(), result))
{
std::cout << "Invalid syntax." << std::endl;
}
std::cout << "The result is " << result << std::endl;
return 0;
}
This generated 309 lines of warnings! They all looked similar to this:
c:\boost\boost/spirit/home/support/terminal.hpp(264) : warning C4348: 'boost::spirit::terminal<boost::spirit::tag::lit>::result_helper' : redefinition of default parameter : parameter 3
c:\boost\boost/spirit/home/support/terminal.hpp(270) : see declaration of 'boost::spirit::terminal<boost::spirit::tag::lit>::result_helper'
c:\boost\boost/spirit/home/support/common_terminals.hpp(142) : see reference to class template instantiation 'boost::spirit::terminal<boost::spirit::tag::lit>' being compiled
The program compiled fine and did what I thought it would do, but I'm wondering how to manage all of these warnings without silencing the useful ones. Is there a way to disable warnings originating from boost, but to preserve the warnings generated by my code? Spirit is a fairly popular library, so I know that there's some way to deal with it.
With VC++ you need to wrap your Boost includes in a few pragmas:
#pragma warning(push)
#pragma warning(disable : 4348)
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#pragma warning(pop)
#include <iostream>
#include <string>
// ...
Add to the disable list as needed, space delimited (docs).
Other compilers typically allow you to tag specified include paths as 'system' paths, and all warnings from headers in system paths are suppressed. For GCC and Clang in particular, use -isystem rather than -I (docs).
I was wondering how boost implemented the Lambda library. I was digging into the implementation but it felt like i'm falling down the rabbit hole...
Can someone please explain shortly how the following code snippet works (Taken from here)?
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
using namespace boost::lambda;
typedef std::istream_iterator<int> in;
std::for_each(
in(std::cin), in(), std::cout << (_1 * 3) << " " );
}
What's going on behind the scenes that creates a functor object that expects an int?
Thanks
I'm trying to find an element in a vector of structs. The code works when searching in a case-sensitive manner. When I try enhancing it to be case-insensitive, I run into two issues.
Simply including boost/algorithm/string.hpp breaks the previously working VS2010 build. The error is "'boost::phoenix::bind' : ambiguous call to overloaded function". Builds OK in Xcode. Any way to disambiguate the bind?
I guess I've got the syntax wrong in the second (commented out) find_if line, adding the istarts_with call. I get errors from the phoenix headers saying "error: no type named 'type'". Assuming issue #1 can be fixed, how should I correct this line?
Thanks!
Code:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp> // This include breaks VS2010!
#include <boost/phoenix/bind.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/stl/algorithm.hpp>
using namespace boost::phoenix;
using boost::phoenix::arg_names::arg1;
using boost::istarts_with;
using std::string;
using std::cout;
// Some simple struct I'll build a vector out of
struct Person
{
string FirstName;
string LastName;
Person(string const& f, string const& l) : FirstName(f), LastName(l) {}
};
int main()
{
// Vector to search
std::vector<Person> people;
std::vector<Person>::iterator dude;
// Test data
people.push_back(Person("Fred", "Smith"));
// Works!
dude = std::find_if(people.begin(), people.end(), bind(&Person::FirstName, arg1) == "Fred");
// Won't build - how can I do this case-insensitively?
//dude = std::find_if(people.begin(), people.end(), istarts_with(bind(&Person::FirstName, arg1), "Fred"));
if (dude != people.end())
cout << dude->LastName;
else
cout << "Not found";
return 0;
}
You'd need two binds to make it work. First define:
int istw(string a, string b) { return istarts_with(a,b); }
and then use the following as the predicate for the find_if:
bind(&istw,bind(&Person::FirstName, arg1),"fred")
Two comments:
Make sure you're using the right bind, namely, use boost::phoenix::bind.
The definition of istw is probably unnecessary but I could not find the right way to replace it.
I am trying to compile the following code:
#include <iostream>
#include <iterator>
#include <vector>
#include <boost/assign/std/vector.hpp>
#include <boost/optional.hpp>
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/algorithm/copy.hpp>
int main( int argc, char ** argv )
{
using namespace boost::assign;
using boost::adaptors::indirected;
std::vector<boost::optional<unsigned> > values;
values += 1u,2u,3u;
boost::copy( values | indirected, std::ostream_iterator<unsigned>( std::cout, " " ) );
std::cout << std::endl;
}
However, I got some errors, e.g. that there is no type named element_type in boost::optional<unsigned>. The reference page page, however, says that the single precondition is the existence of the operator*() unary function. Is there a way to make it work?
This is definitely a bug in Boost, but whether that bug is in Boost.Optional or Boost.Iterator is up for debate (I would say the latter, personally).
However, the fix is trivial -- before including any Boost headers, do this:
#include <boost/optional/optional_fwd.hpp>
#include <boost/pointee.hpp>
namespace boost
{
template<typename P>
struct pointee<optional<P> >
{
typedef typename optional<P>::value_type type;
};
}
Then include other Boost headers as necessary.
Please submit a ticket on the Boost Trac, or at the least post a bug report on the Boost Users mailing list.
Look at the private optional.hpp defined in boost iostreams library here. You will see that it defines a typedef T element_type;
However the actual optional.hpp that you are using defined here does not define it. So that is why the compiler is complaining. I don't know why it was overlooked.
Try using the private optional.hpp from iostreams library to solve this issue. I hope this helps.