Mar*_*ork 2 c++ lambda template-meta-programming
我正在编写一个库,用户提供一个回调作为lambda.在默认情况下,我想只调用lambda并传回一个对象.
现在有一些非平凡的情形,用户也可能想要上下文.所以我希望能够使用相同的回调机制,只允许用户将上下文作为参数添加到他们的lambda中,然后我将传递对象和上下文.
我不能让SFINAE工作.
我已将代码简化为:
#include <string>
#include <iostream>
class Context {};
template<typename F>
struct UseContext
{
// I want to set this value to 0 or 1 based on the parameters
// in F but can't quite get this to work.
enum {value = 0 };
};
template<typename F, typename T, bool useContext = UseContext<F>::value>
struct Caller;
template<typename F, typename T>
struct Caller<F, T, true>
{
void operator()(F& func, Context& context, T& object)
{
func(context, object);
}
};
template<typename F, typename T>
struct Caller<F, T, false>
{
void operator()(F& func, Context&, T& object)
{
func(object);
}
};
template<typename T, typename F>
void doWork(F&& func)
{
Context context;
T object;
/// STUFF
Caller<F,T> caller;
caller(func, context, object);
}
Run Code Online (Sandbox Code Playgroud)
用法:
int main()
{
// if UseContext::value == 0 then this compiles.
// This is the normal situation.
doWork<std::string>([](std::string const& x){ std::cout << x << "\n";});
// if UseContext::value == 1 then this compiles.
// This is if the user wants more context about the work.
// most of the time this extra parameter is not required.
// So I don't want to force the user to add it to the parameter
// list of the lambda.
doWork<std::string>([](Context&, std::string const& x){ std::cout << x << "\n";});
}
Run Code Online (Sandbox Code Playgroud)
或者,如果有更好的方法这样做.
表达SFINAE:
template<class F, class T>
auto call(F& func, Context& context, T& object) -> decltype(func(context, object), void())
{
func(context, object);
}
template<class F, class T>
auto call(F& func, Context&, T& object) -> decltype(func(object), void())
{
func(object);
}
Run Code Online (Sandbox Code Playgroud)
然后就是call(func, context, object).如果两种形式都有效,则这是不明确的.如果你想消除歧义,只需添加一个虚拟参数并执行通常int/ long技巧.