1

我想创建一个函数,它接受一个弱指针和任何类型的仿函数(lambda,std::function等等)并返回一个新仿函数,它只在同时没有删除指针时执行原始仿函数(所以我们假设有具有WeakPointer这种语义的类型)。这应该适用于任何函子,而不必通过模板参数或强制转换明确指定函子签名。

编辑: 一些评论者指出std::function- 我在我的方法中使用的 - 可能根本不需要,lambda也可能不需要(尽管在我原来的问题中我也忘了提到我需要捕获弱指针参数),所以任何解决一般问题的替代解决方案当然也受到高度赞赏,也许我在框外没有足够的想法,而是专注于使用 lambda + std::function。无论如何,这是我到目前为止所尝试的:

template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
    return [=] (ArgumentTypes... args)
    {
        if(pWeakPointer)
        {
            fun(args...);
        }
    };
}

如果我传递一个 ,则无需显式指定参数类型,这很有效std::function,但如果我传递一个 lambda 表达式,则失败。我猜这是因为这个问题std::function中提出的构造函数歧义。无论如何,我尝试了以下帮助程序来捕获任何类型的功能:

template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
    return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}

这现在适用于没有参数但对其他参数失败的 lambda,因为它总是ArgumentTypes...用空集实例化。

我可以想到两个解决问题的方法,但没有设法实现其中任何一个:

  1. 确保std::function为 lambda 创建了正确的(或另一个 Functor 帮助器类型),即带有签名的 lambdaR(T1)导致 astd::function(R(T1))以便ArgumentTypes...正确推断
  2. 不要把它ArgumentTypes...作为模板参数,而是有一些其他的方式(提升?)从 lambda/functor 获取参数包,所以我可以做这样的事情:

-

template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
    return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
4

2 回答 2

3

您不必使用 lambda。

#include <iostream>
#include <type_traits>

template <typename F>
struct Wrapper {
    F f;

    template <typename... T>
    auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
        std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
        return f(std::forward<T>(args)...);
    }
};

template <typename F>
Wrapper<F> wrap(F&& f) {
    return {std::forward<F>(f)};
}

int main() {
    auto f = wrap([](int x, int y) { return x + y; });
    std::cout << f(2, 3) << std::endl;
    return 0;
}
于 2013-06-27T11:00:38.677 回答
1

假设弱指针代替了第一个参数,这就是我将如何使用通用 lambda(带有移动捕获)以及如果 C++ 允许我返回这样的 lambda:

template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
    return [functor = std::forward<Functor>(functor)
           , arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
    {
        if(auto e = arg.lock()) {
            return functor(*e, std::forward<Rest>(rest)...);
        } else {
            // Let's handwave this for the time being
        }
     };
}

如果我们将通用 lambda 手动“展开”为多态函子,则可以将此假设代码转换为实际的 C++11 代码:

template<typename F, typename Pointer>
struct wrap_type {
    F f;
    Pointer pointer;

    template<typename... Rest>
    auto operator()(Rest&&... rest)
    -> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
    {
        if(auto p = lock()) {
            return f(*p, std::forward<Rest>(rest)...);
        } else {
            // Handle
        }
    }
};

template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }

有两个直接的选项可以处理指针已过期的情况:传播异常或返回带外值。在后一种情况下,返回类型将变为 egoptional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )>并将// Handle变为return {};

示例代码以查看所有操作

[ 雄心勃勃的练习:改进代码以便可以使用auto g = wrap(f, w, 4); auto r = g();. 然后,如果还不是这样,请进一步改进它,以便这auto g = wrap(f, w1, 4, w5);也是可能的并且“做正确的事”。]

于 2013-06-27T13:15:13.097 回答