简体   繁体   English

C++17 装饰 lambda 或成员 function 非捕获 lambda

[英]C++17 decorate lambda or member function with non-capturing lambda

I'm trying to craft a function that returns a non-capturing lambda (so it can be converted to a function pointer) that decorates an inner function, where the inner function can be either a lambda or a member function pointer.我正在尝试制作一个 function,它返回一个非捕获 lambda(因此它可以转换为一个 function 指针)装饰一个内部 function,其中内部 function 可以是 8835508.86348 指针或 84a71988 指针

Compiler Explorer link for reference, which I'll dissect in the following. Compiler Explorer 链接供参考,我将在下面对其进行剖析。

I've come up with two strategies, one for lambdas and the other for member functions.我提出了两种策略,一种用于 lambda,另一种用于成员函数。 Specifically, for lambdas具体来说,对于 lambda

template <typename Callable>
auto decorate_lambda(Callable&& lambda) {
    static const Callable callable = std::forward<Callable>(lambda);

    return [](auto... args) {
        return 100 + callable(std::forward<decltype(args)>(args)...);
    };
}

Saving off the lambda as a static allows callable to be used in a non-capturing lambda. This is fine because the decorate_lambda template instantiation will be unique for each lambda (IIRC).将 lambda 保存为static允许在非捕获 lambda 中使用callable 。这很好,因为decorate_lambda模板实例化对于每个 lambda (IIRC) 都是唯一的。

For member functions the strategy is somewhat different (note the template parameter)对于成员函数,策略有些不同(注意模板参数)

template <auto callable>
auto decorate_memfn() {
    return [](auto... args) {
        return 100 + std::mem_fn(callable)(std::forward<decltype(args)>(args)...);
    };
}

I can then do something like然后我可以做类似的事情

const auto decorated_lambda =
    decorate_lambda([](int i) { return i + 1; });

const auto decorated_memfn =
    decorate_memfn<&Worker::work>();

int (*lambda_fnptr)(int) = decorated_lambda;
int (*memfn_fnptr)(Worker&, int) = decorated_memfn;

resulting in function pointers that can be used eg in a C interface (ultimately).导致 function 指针可用于例如 C 接口(最终)。

The end result that I would like is to roll decorate_lambda and decorate_memfn into a single decorate(lambda_or_memfn) function (using template specialisation, if constexpr , or whatever).我想要的最终结果是将decorate_lambdadecorate_memfn滚动到单个decorate(lambda_or_memfn) function (使用模板专业化, if constexpr ,或其他)。 Eg例如

decorate([](int i) { return i + 1; });
decorate(&Worker::work);

Ie essentially I would like to have decorate_memfn(&Worker::work) rather than decorate_memfn<&Worker::work>() .即基本上我想要decorate_memfn(&Worker::work)而不是decorate_memfn<&Worker::work>() The problem is that问题是

  • Passing a member function pointer as a parameter, rather than template argument, means the member function pointer is no longer considered a static/global variable within decorate_memfn .将成员 function 指针作为参数而不是模板参数传递,意味着成员 function 指针不再被视为decorate_memfn中的静态/全局变量。 Is there a way to force the compiler to recognize that a parameter is from a static/global and hence allow it's use within a lambda without capturing?有没有办法强制编译器识别参数来自静态/全局参数,从而允许它在 lambda 中使用而不捕获?
  • Doing something similar to decorate_lambda with it's static trick doesn't work for member function pointers because the template instantiation is not necessarily unique (ie if two Callable s have the same signature).使用static技巧做一些类似于decorate_lambda的事情对成员 function 指针不起作用,因为模板实例化不一定是唯一的(即如果两个Callable具有相同的签名)。 Maybe there is a way to make it unique, though?不过,也许有办法让它变得独一无二?

I understand C++20 could help, but unfortunately I'm stuck with C++17.我知道 C++20 可以提供帮助,但不幸的是我被 C++17 困住了。

Any hints much appreciated!非常感谢任何提示!

First, your decorate_lambda is buggy: it silently breaks if you call it with a stateful callable.首先,你的decorate_lambda有问题:如果你用有状态的可调用函数调用它,它会无声地中断。 As a simple check, you could allow callables only if std::is_empty_v is true.作为一个简单的检查,您可以仅在std::is_empty_v为真时才允许调用。


The end result that I would like is to roll decorate_lambda and decorate_memfn into a single decorate(lambda_or_memfn) function我想要的最终结果是将 decorate_lambda 和 decorate_memfn 合并为一个 decorate(lambda_or_memfn) function

You can use std::integral_constant您可以使用std::integral_constant

template<auto x>
inline constexpr std::integral_constant<decltype(x), x> constant{};

template<typename T, typename F, F T::* x>
auto decorate(std::integral_constant<F T::*, x>)
{
    return [](auto&&... args) {
        return 100 + std::mem_fn(x)(decltype(args)(args)...);
    };
}

auto d = decorate(constant<&Worker::work>);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM