使用 Synxis 提供的指向 ecatmur 答案的链接,我设法编写了一些我想要的东西。我重写了模板以使用 typedef,而不是使用 using 关键字的新模板别名,因此代码可以在较旧的编译器上运行。如果其他人想做类似的事情,我已经包含了下面的代码来展示它是如何完成的:
template<typename T> struct remove_class { };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)> { typedef R(*type)(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const> { typedef R(*type)(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile> { typedef R(*type)(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile> { typedef R(*type)(A...); };
template<typename T>
struct get_function_signature {
typedef typename remove_class<decltype(&std::remove_reference<T>::type::operator())>::type type;
};
template<typename R, typename... A>
struct get_function_signature<R(A...)> { typedef R(*type)(A...); };
template<typename R, typename... A>
struct get_function_signature<R(&)(A...)> { typedef R(*type)(A...); };
template<typename R, typename... A>
struct get_function_signature<R(*)(A...)> { typedef R(*type)(A...); };
// ***************************************************************************
template<typename T> struct num_args {};
template<typename R, typename... A>
struct num_args<R(*)(A...)> { static const int value = sizeof...(A); };
template<typename C, typename R, typename... A>
struct num_args<R(C::*)(A...)> { static const int value = sizeof...(A); };
// ***************************************************************************
template<typename Lambda, int> struct callWithArgsImpl {};
template<typename Lambda>
struct callWithArgsImpl<Lambda, 1> {
static void doIt(Lambda callback, Object* pObj, int arg) { callback(pObj); }
};
template<typename Lambda>
struct callWithArgsImpl<Lambda, 2> {
static void doIt(Lambda callback, Object* pObj, int arg) { callback(pObj, arg); }
};
template<typename Lambda, int N>
void callWithArgs(Lambda callback, Object* pObj, int arg)
{
callWithArgsImpl<Lambda, N>::doIt(callback, pObj, arg);
}
// ***************************************************************************
template<typename Lambda>
void doSomething(int x, Lambda callback)
{
// some code here which gets a pointer to an Object (pObj) and an
// extra piece of information about where the object came from (arg1)
const int numArgs = num_args<typename get_function_signature<Lambda>::type>::value;
callWithArgs<Lambda, numArgs>(callback, pObj, arg1);
}
这允许代码调用 doSomething() 函数,传入一个始终需要 Object* 参数的兰巴表达式,但如果不需要,可以省略第二个参数。所以以下两行都有效:
doSomething(5, [] (Object* pObj) { printf("lambda called with no arg1\n"); } );
doSomething(2, [] (Object* pObj, int arg1) { printf("lambda called with arg1=%d\n", arg); } );
它有效,但我不禁觉得它有效,尽管有语言规范,而不是因为它。使用 lambda 表达式作为回调函数似乎是一件很自然的事情。而且我绝对可以看到我想要指定具有不同签名的回调的情况。这应该比这更容易做到......