根据lambda签名选择类型

时间:2014-08-12 09:24:49

标签: c++ templates c++11 lambda template-meta-programming

我正在尝试根据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 &) { }
  • 的lambda
  • 形式为[](B const &) { }
  • 的lambda
  • Callback的实例或从中派生的类

T_Callback是一个lambda,应该返回从Callback派生的包装类(CallbackFunctionACallbackFunctionB),否则对回调类型本身的引用应该是返回。

正如我所说,上面的代码工作得很好,但我想知道它是否可以简化,即不再需要testanytestlambda函数。

2 个答案:

答案 0 :(得分:2)

你想说的是什么:

  • [](A const &) { }形式的lambda应映射到CallbackFuncionA
  • [](B const &) { }形式的lambda应映射到CallbackFunctionB
  • 类Callback的实例或从中派生的类应映射到自身

你实际拥有的东西:

  • 只有一个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)

根据您的规格,您需要:

  1. 用一个定义的成员operator()来区分(lambda)类与从Callback派生的类(显然假设没有一个成员运算符())的一步,SFINAE的使用是合适的技术(impl with testany)。

  2. 以及另一个区分找到的成员运算符的不同参数类型(A和B)的步骤(impl with testlamda)。

  3. 在一个步骤中组合这些步骤需要在从typedef测试调用testany时访问operator()以及解析是否存在这样的成员函数,这对我来说似乎是不可能的。