我正在尝试根据lambda表达式的签名确定一个类型。
我已经提出了以下代码,它有效,但我想知道是否有更简单的方法可以解决它。我发布了a full working example on ideone。
template <typename T_Callback>
class CallbackType {
private:
template <typename T>
static CallbackFunctionA<T> testlambda(void (T::*op)(A const &) const);
template <typename T>
static CallbackFunctionB<T> testlambda(void (T::*op)(B const &) const);
template <typename T>
static decltype(testlambda<T>(&T::operator())) testany(int);
template <typename T>
static T &testany(...);
public:
typedef decltype(testany<T_Callback>(0)) type;
};
简而言之,T_Callback
可以是:
[](A const &) { }
[](B const &) { }
Callback
的实例或从中派生的类它T_Callback
是一个lambda,应该返回从Callback
派生的包装类(CallbackFunctionA
或CallbackFunctionB
),否则对回调类型本身的引用应该是返回。
正如我所说,上面的代码工作得很好,但我想知道它是否可以简化,即不再需要testany
和testlambda
函数。
答案 0 :(得分:2)
你想说的是什么:
[](A const &) { }
形式的lambda应映射到CallbackFuncionA
[](B const &) { }
形式的lambda应映射到CallbackFunctionB
你实际拥有的东西:
operator()
没有返回并且有一个类型为const A&
的参数的仿函数将映射到CallbackFunctionA
operator()
没有返回并且有一个类型为const B&
的参数的仿函数将映射到CallbackFunctionB
我的建议:定义一个这样的简单转发器,以便在可能的情况下调用:
template<class X, class ARG...>
static auto may_invoke(const X& x, ARG&&... arg)
-> decltype(x(std::forward<ARG>(arg)...))
{ return x(std::forward<ARG>(arg)...); }
struct not_invoked {};
template<class X>
constexpr static not_invoked may_invoke(const X&, ...)
{ return {}; }
此外,测试人员是否可以调用它很好:
template<class X, class ARG...>
constexpr bool does_invoke(const X& x, ARG&&... arg)
{ return !std::is_same<not_invoked,
decltype(may_invoke(x, std::forward<ARG>(arg)...))>::value; }
这使您可以同时使代码更通用,测试更严格。
答案 1 :(得分:0)
根据您的规格,您需要:
用一个定义的成员operator()来区分(lambda)类与从Callback派生的类(显然假设没有一个成员运算符())的一步,SFINAE的使用是合适的技术(impl with testany
)。
以及另一个区分找到的成员运算符的不同参数类型(A和B)的步骤(impl with testlamda
)。
在一个步骤中组合这些步骤需要在从typedef测试调用testany时访问operator()以及解析是否存在这样的成员函数,这对我来说似乎是不可能的。