Using boost :: optional to create optional std :: function arguments
I have a method that accepts four optional callbacks. I want to be able to use lambdas as callbacks, but I, since these callbacks are optional and require a default, I thought I would use boost :: optional.
Here's a direct copy-paste from my code:
typedef std::function<bool(const GameObjectRef &a, const GameObjectRef &b, cpArbiter *arbiter)> EarlyCollisionCallback;
typedef std::function<void(const GameObjectRef &a, const GameObjectRef &b, cpArbiter *arbiter)> LateCollisionCallback;
typedef boost::optional<EarlyCollisionCallback> NullableEarlyCollisionCallback;
typedef boost::optional<LateCollisionCallback> NullableLateCollisionCallback;
virtual void addCollisionMonitor(cpCollisionType a, cpCollisionType b,
NullableEarlyCollisionCallback onCollisionBegin = boost::none,
NullableEarlyCollisionCallback onCollisionPreSolve = boost::none,
NullableLateCollisionCallback onCollisionPostSolve = boost::none,
NullableLateCollisionCallback onCollisionSeparate = boost::none);
The idea is that later on I could pass the lambda as a callback, say for the physics engine's "preSolve" pass, and ignore the other optional parameters. It might be bad design, I will probably write about it differently. But the real question here is C ++. When I try to call this, I get compiler errors on the calling site:
addCollisionMonitor(CollisionType::ENEMY, CollisionType::PLAYER,
//onCollisionBegin
[](const GameObjectRef &enemy, const GameObjectRef &player, cpArbiter *arb)->bool{
CI_LOG_D("Enemy: " << enemy->getName() << " contact player: " << player->getName());
return true;
});
No viable conversion from '(lambda at / Users /..../ GameLevel.cpp: 249: 8)' to 'NullableEarlyCollisionCallback' (aka 'optional &, const shared_ptr &, cpArbiter *) →')
However, if I explicitly wrap the lambda in NullableEarlyCollisionCallback (), it works:
addCollisionMonitor(CollisionType::ENEMY, CollisionType::PLAYER,
//onCollisionBegin
NullableEarlyCollisionCallback([](const GameObjectRef &enemy, const GameObjectRef &player, cpArbiter *arb)->bool{
CI_LOG_D("Enemy: " << enemy->getName() << " contact player: " << player->getName());
return true;
}));
I'm curious why, in this case, the compiler can't just convert the lambda to the optional type <>. What am I missing?
This is using Xcode 9 beta3.
source to share
A std::function
is constructive of a nullptr_t
. So, when converted to, the bool
value will be false
. If it contains a function object, then true
.
Documentation:
http://en.cppreference.com/w/cpp/utility/functional/function/function
http://en.cppreference.com/w/cpp/utility/functional/function/operator_bool
demonstration:
#include <functional>
struct GameObjectRef {};
struct cpArbiter {};
struct cpCollisionType {};
typedef std::function<bool(const GameObjectRef &a, const GameObjectRef &b, cpArbiter *arbiter)> EarlyCollisionCallback;
typedef std::function<void(const GameObjectRef &a, const GameObjectRef &b, cpArbiter *arbiter)> LateCollisionCallback;
struct MyThing
{
EarlyCollisionCallback a_, b_;
LateCollisionCallback c_, d_;
virtual void addCollisionMonitor(cpCollisionType a, cpCollisionType b,
EarlyCollisionCallback onCollisionBegin = nullptr,
EarlyCollisionCallback onCollisionPreSolve = nullptr,
LateCollisionCallback onCollisionPostSolve = nullptr,
LateCollisionCallback onCollisionSeparate = nullptr)
{
a_ = std::move(onCollisionBegin);
b_ = std::move(onCollisionPreSolve);
c_ = std::move(onCollisionPostSolve);
d_ = std::move(onCollisionSeparate);
}
void call_callbacks(const GameObjectRef &a, const GameObjectRef &b, cpArbiter *arbiter)
{
if (a_) a_(a, b, arbiter);
if (b_) b_(a, b, arbiter);
if (c_) c_(a, b, arbiter);
if (d_) d_(a, b, arbiter);
}
};
int main()
{
MyThing m;
}
source to share