Binding overloaded function - c++

This code was developed and originally worked with boost 1.48. Since updating to boost 1.52 it refuses to compile.
boost::signals2::signal<void (uint32_t)> foo;
boost::shared_ptr<boost::circular_buffer<uint32_t>> _foo_buffer = new boost::circular_buffer<uint32_t>(32);
_foo.connect(boost::bind(&boost::circular_buffer<uint32_t>::push_front, _foo_buffer, _1));
The goal is to have foo(42) place 42 on the front of the circular buffer.
My compile error is No matching function for call to 'bind' with a bunch of Candidate template ignored: couldn't infer template argument 'R' and similar template errors.
I suspect the problem is that between the boost versions I'm using, the definition for push_front changed from
void push_front(const_reference item = value_type());
to the three definitions
void push_front(param_value_type);
void push_front(rvalue_type);
void push_front();
and it's confused my compiler.
I would really appreciate some help with the syntax of a connect expression that will work with the new boost library. Thanks

let's say you have the two functions
void foo( int ) {}
void foo( double* ) {}
then you can't just write &foo since that would be ambiguous.
but you can use static_cast to establish a context where only one candidate is possible, thusly:
static_cast<void(*)(int)>( &foo )
which gives you the address of the first one, and ditto for the second one.
that said, it looks like you can simplify things by using a C++ lambda function instead of a bind (for a C++03 compiler alternatively define your own functot).

Related

function overloading with std::function and generic lambdas: std::string preferred over int

When trying to compiling this, suprisingly, it gives an error because the auto parameter of the lambda function has been resolved to std::string, and the compiler doesn't know how to convert std::string to int or Widget when calling test.
But, I wonder why the compiler has choosen the second invok function instead of the first one, when the first one would succeed:
#include <string>
#include <functional>
struct Widget {};
bool test(int );
bool test(Widget );
void invok(std::function<bool(int)> ); // #1
void invok(std::function<bool(std::string)> ); // #2
int main()
{
// error: unresolved overloaded function type
// invok(test);
// still error: no known conversion from std::string to
// int or Widget
invok([](auto&& x) {
return test(std::forward<decltype(x)>(x));
});
}
That example has been copied from a C++ proposal.
The compiler didn't choose #2. It's trying to decide if it can choose #2.
To do that, it asks "can this generic lambda be converted to std::function<bool(std::string)>"?
std::function's converting constructor says "only if it's callable with a std::string rvalue and the result type is convertible to bool".
Compiler tries that, deduce auto as std::string, substitute into the signature of the function call operator...success! Oops, the return type is auto, and it needs an actual type to answer the "is convertible" question. So it instantiates the body of the function call operator template to figure out the return type.
Ouch. The body isn't valid for std::string after all. Hard error and explosions follow.
Your overload remains ambiguous (sort of), but along the way to determining that your code runs into a hard error when trying out the two possibilities (passing an int or a string).
To see the ambiguity, add a ->bool to your lambda so it doesn't have to compile the body to determine the return value.
The body of a lambda is not in an area where a subsitution failure results in not an error. Instead you get a hard error there.
The easy fix is to make your lambda take an int explicitly.
If you want a generic solution:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
and then
invok(OVERLOADS_OF(test));
does (at least closer to) the right thing.
This macro moves the failure from the body of the lambda, to a trailing return type. And the failure (that string cannot be passed to test) now occurs in a context where substitution failure causes not an error (SFINAE). So everything works.
The exact rules for what is SFINAE friendly and what is not require reading the standard. However, the rule of thumb is that works well is that compilers don't have to treat errors in bodies of functions as substitution errors, and that accessing the contents of an undefined class is a hard error. The first because it seemed a reasonable place to draw a line and make it easier for compiler writers; the second because the alternative is insanity or ODR bug bait.
In practice, the standards SFINAE rules are more arcane, and last I checked in C++14 there was an omission of SFINAE being required during template class partial specialization: every compiler supported it. But maybe I misread it. In any case, the rule of thumb I use seems just as useful as the standard text. Neither are going to be perfect.

QSet<func pointer> does not compile by gcc

I'm trying to use QSet for storing a list of function pointers. See this code for more details. The problem is that this code does not compile by gcc/mingw. MSVC compiles it normally. What am I doing wrong?
typedef intptr_t (*UikHook)(intptr_t);
...
typedef struct
{
QSet<UikHook>* qsetSubscribers;
//QMutex* qmutexHook;
} THookableEvent;
...
THookableEvent* p = qmapHooks_.value(name);
if (p->qsetSubscribers == 0)
p->qsetSubscribers = new QSet<UikHook>();
p->qsetSubscribers->insert(hookProc);
error: no matching function for call to ‘qHash(long int (* const&)(long int))’
Perhaps, I should to declare operator== and function qHash() for type UikHook as it said in the docs, but I dont know how to do it because when I'm declaring opertator==, I get the following error:
inline bool operator==(const UikHook &e1, const UikHook &e2)
error: ‘bool operator==(intptr_t (* const&)(intptr_t), intptr_t (* const&)(intptr_t))’
must have an argument of class or enumerated type
P.S. I'm using Qt 5.8, gcc 6.2, msvc2015
Update: Solved by replacing QSet to QVector.
You can't define an operator== for built-in types, such as pointers, integers or floating-point numbers. They already have it. You just need to provide a qHash.
Using function pointers is not really the best practice in C++. In early C++ versions, functors were used instead. Since C++11, there are real function objects. You can convert a function pointer to an object via std::function() (Reference).
If the compilers you listed are the ones you need to support, I strongly suggest using std::function instead of function pointers.
Try (warning, brain compile):
template <typename R, typename ...A>
inline uint qHash(R (*)(A...) const f) noexcept
{
return std::hash<R (*)(A...)>()(f);
}
Qt is in a fix here, since it can't use the STL and hashing function pointers is somewhat compiler specific.

Compile error: boost::promise<T>::set_value(const T&) doesn't exist

I'm having problems with Boost.Thread's futures: I can't seem to put anything but a primitive type into a promise, future, or packaged task.
Here is a minimal testcase:
#include <boost/thread/future.hpp>
struct foo
{
foo(int i_): i(i_) {}
int i;
};
int main()
{
// A const future isn't much use, but I needed to prove
// the problem wasn't me trying to copy a unique_future
const boost::unique_future<foo>& fut = boost::make_ready_future( foo(42) );
}
With BOOST_THREAD_USES_MOVE defined before including the Boost.Future header I get the following error with gcc 4.8.2 and Boost 1.55 (full output here):
../../deps/boost/include/boost/thread/future.hpp:3634:5: error: no matching function for call to ‘boost::promise<foo>::set_value(const foo&)’
p.set_value(boost::forward<future_value_type>(value));
^
There seems to be no overload of promise::set_value() that takes a const lvalue reference. Looking at promise and future_traits in future.hpp it seems that the const lvalue ref overload will only exist when BOOST_NO_CXX11_RVALUE_REFERENCES is undefined. That makes no sense to me however...surely the const lvalue ref overload is needed precisely when there are no rvalue references? (Note this happens even if I pass a mutable lvalue ref to make_ready_future()).
If I don't define BOOST_THREAD_USES_MOVE it fails compilation with the following error (full output here):
../../deps/boost/include/boost/thread/detail/move.hpp:183:54: error: no matching function for call to boost::unique_future<foo>::unique_future(boost::unique_future<foo>)’
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE.move()
^
Have I missed something?
It seems from the boost-users mailing list that this is a bug in Boost and is also present in 1.56 - looks like it's fundamentally broken in C++03 mode.
Bug report: https://svn.boost.org/trac/boost/ticket/10340

Passing lambda with parameter

I would like to pass a lambda to a funciton.
This
boost::function<void()> fncPtr(boost::bind<void>([](){/* something */}));
works, but if the lambda had a parameter, I don't know how to do it properly:
boost::function<void(bool)>
fncPtr(boost::bind<void,bool>([](bool){/* something */}, _1));
does not work.
Where I am wrong?
How to pass lambda with argument(s)?
I would like to do this in a member function.
So in "global scope"(is it the name?) this method above works fine.
This works fine for me with GCC4.5:
#include <boost/bind.hpp>
#include <boost/function.hpp>
int main() {
boost::function<void(bool)>
fncPtr(boost::bind<void>([](bool){/* something */}, _1));
}
It doesn't need the type of the parameters. Those parameter types could be templated anyway (for some functors), so in general it cannot depend on them. It only needs the return type.
Incidentally, it even works for me when I pass <void, bool>, but only when the lambdas has no captures. I think that this may work for me because GCC4.5 supports conversion of lambdas to function pointer types, when the lambdas has no capture clause. <void, bool> would make bind have a candidate that accepts a function pointer, and make the lambda convert to that. Your compiler apparently doesn't support that special conversion yet (but the FDIS requires it).
So, just pass <void> only, and it should work.
I summed up some techniques here on Ideone. Note, I used the C++0x versions, the Boost ones should work just fine too.
It really depends though on what your function wants as a parameter though. If it is simply templated or takes a (std::|boost::)function, then a simple lambda will do. No need for complicated binding or packaging in an extra (std::|boost::)function.
You have a problem in the compiler probably. I have an error in Visual Studio 2010 too. You can help compiler to convert a lambda to a function using helper function:
template <typename T>
void closureToFunction(bool x){ T f; return f(x); }
int main()
{
auto exp = [](bool x){/* something */};
boost::function<void(bool)> fncPtr(
boost::bind( closureToFunction<decltype(exp)>, _1) );
return 0;
}

Using std::bind2nd with references

I have a simple class like this:
class A
{
public:
void f(const int& n)
{
std::cout<<"A::f()" << n <<"\n";
}
};
and I am trying to use it like this:
std::vector<A> vec;
A a;
vec.push_back(a);
std::for_each(vec.begin(), vec.end(), std::bind2nd(std::mem_fun_ref(&A::f), 9));
But when I compile the code I get the following error somewhere inside functional header file:
error C2529: '_Right' : reference to
reference is illegal
If I remove the reference in the parameter f() it compiles fine. How do I resolve this? I don't want to remove the reference as in my real code the copying of the object is quite costly. Also, I am not using boost.
You can't do that easily, sorry. Just consider it one of those cases not covered by std::bind1st and std::bind2nd (kinda like 3-argument functions etc). Boost would help - boost::bind supports references transparently, and there's also boost::ref.
If your implementation supports TR1 - latest g++ versions and VC++2008 SP1 both do - then you can use std::tr1::bind, which is for the most part same as boost::bind, but standardized.
I dont believe you can bind parameters to a method that takes references. (not in the STL, I think the boost versions may let you do it but I am not sure)
You will need to roll your own.
struct CallF
{
CallF(int const& data): m_data(data) {}
void operator()(A& val) const
{
val.f(m_data);
}
int const& m_data;
};
Use like this:
std::for_each(vec.begin(), vec.end(), CallF(9));
I've been bitten by the same problem. If you look into the C++ standard, you'll see that it's actually a "library defect". A conforming C++ implementation simply can't deal with reference parameters. mem_fun_ref returns an object of a class that has nested typedefs (
argument_type, first_argument_type, second_argument_type
) where references are not stripped away. bind1st and bind2nd are specified to have an operator() wich takes references as parameters. In case argument_type is a reference already this will fail to compile.
One solution might be to replace memfunref with your own template magic and strip away references for the nested argument_type typedefs.
Actually, the compilers error message tells the whole story:
error C2529: '_Right' : reference to reference is illegal
std:: binders take their arguments as references - you cant pass a reference to a reference.
No way.