Reputation: 639
Assume we have a class template like this:
template <typename baseT, typename ...argTs>
class CCallable : public baseT
{
public:
CCallable(std::function<bool(argTs...)> lambda)
: m_lambda(lambda) {
}
bool Invoke(argTs ...args) override {
return m_lambda(args...);
}
private:
std::function<bool(argTs...)> m_lambda;
};
And assume we have a function template callback
implemented, probably similar to this pseudo code:
template <typename baseT, typename lambdaT>
CCallable<baseT, typename lambdaT::argTs...> callback(lambdaT lambda)
{
return CCallable<baseT, typename lambdaT::argTs...>(lambda);
}
so that we are able to do this:
auto&& functor = callback<CBase>([](int x, int y, int *sum)->bool{
*sum = x + y;
return true;
});
// Start passing functor around and then...
int sum;
functor.Invoke(7, 42, &sum);
Please note that the parameter types of the lambda are not passed to callback
as its template type arguments.
How can we implement a function template like this, to save the users from typing more codes like:
auto&& functor = callback<CBase, int, int, int*>([](int x, int y, int *sum)->bool{
*sum = x + y;
return true;
});
Thanks.
By the way, why I'm asking this is because Microsoft::WRL
provides a similar template named Callback
which is called many times in an opensource library I want to use. However, I prefer to build the library with GNU C++ instead of Visual C++. Therefore, it seems inevitable that I have to implement a Microsoft::WRL::Callback
-like template or macro myself.
Upvotes: 1
Views: 266
Reputation: 26292
With C++17 CTAD, you could harness deduction guides for std::function
:
template<class T>
struct Identity { };
template<typename baseT, typename ...argTs>
class CCallable : public baseT {
public:
CCallable(std::function<bool(argTs...)> lambda, Identity<baseT> = {})
: m_lambda(lambda) {
}
bool Invoke(argTs ...args) override {
return m_lambda(args...);
}
private:
std::function<bool(argTs...)> m_lambda;
};
template<typename baseT, typename lambdaT>
auto callback(lambdaT lambda) {
return CCallable(std::function(lambda), Identity<baseT>{});
}
CTAD is all-or-nothing, so the type baseT
is wrapped into Identity
to make it deducible.
Upvotes: 3