【问题标题】:Choosing type based on lambda signature根据 lambda 签名选择类型
【发布时间】:2014-08-12 09:24:49
【问题描述】:

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

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

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

【问题讨论】:

  • 为什么std::function 不适合你?另外,您知道通用 lambda 表达式吗?
  • @Deduplicator std::function 不起作用,因为我需要添加 lambda 未定义的占位符运算符。当 lambda 匹配时,包装器调用指定的 lambda 而不是占位符。有关详细信息,请参阅 ideone 上的示例。我不知道通用 lambda,谢谢。这可能是未来定义一个可以同时接受AB 的回调的替代方案。

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


【解决方案1】:

你说你想要什么:

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

你实际拥有的:

  • 只有一个 operator() 不返回任何内容并且有一个 const A&amp; 类型的参数的函子将被映射到 CallbackFunctionA
  • 只有一个operator() 不返回任何内容并且有一个const B&amp; 类型的参数的函子将被映射到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; }

这允许您同时使您的代码更通用,测试更严格。

【讨论】:

  • 很好的建议,谢谢!目前,这允许我用任何东西(例如may_invoke(0, ...))调用我的执行程序,但我想这就是测试人员的用途。
【解决方案2】:

根据您的规格,您需要:

  1. 将具有一个已定义成员 operator() 的 (lambda) 类与从 Callback 派生的类(显然假定不具有确切的一个成员 operator())区分开来的一步,其中 SFINAE 的使用是合适的技术(impl with testany)。

  2. 还有一个步骤来区分找到的成员运算符的不同参数类型(A 和 B)(使用 testlamda 实现)。

将这些步骤合二为一将需要在 typedef 测试中访问 testany 调用中的 operator() 以及解析此类成员函数是否存在,这对我来说似乎是不可能的。

【讨论】:

    猜你喜欢
    • 2016-05-31
    • 2021-02-25
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 2016-10-17
    • 2018-01-21
    • 2012-08-30
    • 1970-01-01
    相关资源
    最近更新 更多