是否可以在 C++11 之前创建函数局部闭包?

发布于 2024-11-02 02:59:40 字数 1648 浏览 1 评论 0原文

借助 C++11,我们获得了 lambda,并且可以在我们真正需要的地方(而不是在它们不真正属于的地方)即时创建函数/函子/闭包。
在 C++98/03 中,创建函数本地函子/闭包的一个好方法如下:

struct{
  void operator()(int& item){ ++item; }
}foo_functor;
some_templated_func(some_args, foo_functor);

遗憾的是,您不能使用模板的本地类型(Visual Studio 允许在启用语言扩展的情况下这样做)。我的思路是这样的:

struct X{
  static void functor(int& item){ ++item; }
};
some_templated_func(some_args, &X::functor);

明显的问题是,你无法保存任何状态,因为本地结构/类不能有静态成员。
我解决该问题的下一个想法是混合使用 std::bind1st 和 std::mem_fun 以及非静态方法和方法。变量,但不幸的是 std::mem_fun 不知何故被 std::mem_fn(&X::functor) 阻塞,这又可能是因为本地结构/类不能在模板中使用:

// wanted, not working solution
struct X{
  int n_;
  X(int n) : n_(n) {}
  void functor(int& item) const { item += n_; }
};
X x(5);
some_templated_func(some_args,std::bind1st(std::mem_fun(&X::functor),&x));

在 VC9 和 VC9 下失败VC10(带有 /Za,禁用语言扩展)出现以下错误

error C2893: Failed to specialize function template 'std::const_mem_fun1_t<_Result,_Ty,_Arg> std::mem_fun(_Result (_Ty::* )(_Arg) const)'
With the following template arguments:
'void'
'main::X'
'int &'

或者在 gcc 4.3.4 下出现此错误

error: no matching function for call to ‘mem_fun(void (main()::X::*)(int&))’

有趣的是,VC9 / VC10 仍然对上面的示例感到窒息,即使启用了语言扩展

error C2535: 'void std::binder1st<_Fn2>::operator ()(int &) const' : member function already defined or declared

: ,标题中所述的功能是否可以以某种方式实现?或者我在最后一个示例中使用 std::bind1ststd::mem_fun 时犯了错误吗?

With C++11, we get lambdas, and the possibility to create functions/functors/closures on-the-fly where we actually need them, not somewhere where they don't really belong.
In C++98/03, a nice way to make function-local functors/closures would've been the following:

struct{
  void operator()(int& item){ ++item; }
}foo_functor;
some_templated_func(some_args, foo_functor);

Sadly, you can't use local types for templates (Visual Studio allows this with language extensions enabled). My train of though then went the following way:

struct X{
  static void functor(int& item){ ++item; }
};
some_templated_func(some_args, &X::functor);

The obvious problem being, that you can't save any state, since local structs/classes can't have static members.
My next thought to solving that problem was using a mix of std::bind1st and std::mem_fun and non-static methods & variables, but unfortunately std::mem_fun somehow chokes with std::mem_fn(&X::functor), which again might be because local struct/classes can't be used in templates:

// wanted, not working solution
struct X{
  int n_;
  X(int n) : n_(n) {}
  void functor(int& item) const { item += n_; }
};
X x(5);
some_templated_func(some_args,std::bind1st(std::mem_fun(&X::functor),&x));

Fails under VC9 & VC10 (with /Za, disabled language extensions) with the following error

error C2893: Failed to specialize function template 'std::const_mem_fun1_t<_Result,_Ty,_Arg> std::mem_fun(_Result (_Ty::* )(_Arg) const)'
With the following template arguments:
'void'
'main::X'
'int &'

Or under gcc 4.3.4 with this error

error: no matching function for call to ‘mem_fun(void (main()::X::*)(int&))’

Funnily enough, VC9 / VC10 still chokes on the above example, even with language extensions enables:

error C2535: 'void std::binder1st<_Fn2>::operator ()(int &) const' : member function already defined or declared

So, is the functionality stated in the title somehow, anyhow achievable? Or am I making a mistake in the last example in how I use std::bind1st or std::mem_fun?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

╰沐子 2024-11-09 02:59:40

bind1st 仅适用于二进制函数,并且一般来说它非常受限制。 mem_fn 仅适用于非静态成员函数;对于您的应用程序,您需要 ptr_fun

实际上,C++03 中完成这项工作的最佳工具是 Boost Bind,或者我将在此处使用 tr1::bind 进行演示,(在我看来)它更可移植。

#include <tr1/functional>
#include <iostream>
#include <algorithm>

using namespace std::tr1::placeholders;

int nums[] = { 1, 2, 4, 5, 6, 8 };

int main() {
    struct is_multiple {
        static bool fn( int mod, int num ) { return num % mod == 0; }
    };

    int *n = std::find_if( nums, nums + sizeof nums/sizeof*nums,
                        std::tr1::bind( is_multiple::fn, 3, _1 ) );

    std::cout << n - nums << '\n';
}

bind1st only works for binary functions, and in general it's very restricted. mem_fn works with non-static member functions only; for your application you would want ptr_fun.

Really the best tool for the job in C++03 is Boost Bind, or I'll demonstrate here with tr1::bind which is (in my opinion) more portable.

#include <tr1/functional>
#include <iostream>
#include <algorithm>

using namespace std::tr1::placeholders;

int nums[] = { 1, 2, 4, 5, 6, 8 };

int main() {
    struct is_multiple {
        static bool fn( int mod, int num ) { return num % mod == 0; }
    };

    int *n = std::find_if( nums, nums + sizeof nums/sizeof*nums,
                        std::tr1::bind( is_multiple::fn, 3, _1 ) );

    std::cout << n - nums << '\n';
}
小…楫夜泊 2024-11-09 02:59:40

是的,您可以,但您必须实现接口中声明的一个或多个虚拟方法。

template<typename Arg, typename Result>
struct my_unary_function
{
    virtual Result operator()(Arg) = 0;
};

template<typename Arg, typename Result>
struct my_unary_functor
{
    my_unary_function<Arg, Result> m_closure;
    my_unary_functor(my_unary_function<Arg, Result> closure) : m_closure(closure) {}
    Result operator()(Arg a) { return m_closure(a); }
};

template<typename T, TFunctor>
void some_templated_function( std::vector<T> items, TFunctor actor );

然后,您可以定义并使用本地闭包:

void f()
{
    std::vector<int> collection;

    struct closure : my_unary_function<int, int>
    {
        int m_x, m_y;
        closure(int x, int y) : m_x(x), m_y(y) {}
        virtual int operator()(int i) const { cout << m_x + m_y*i << "\t"; return (m_x - m_y) * i; }
    };

    some_templated_function( collection, my_unary_functor<int,int>(closure(1, 5)) );
}

此改进归功于 @Omnifarious (my_unary_functor不需要):

void f()
{
    std::vector<int> collection;

    struct closure : my_unary_function<int, int>
    {
        int m_x, m_y;
        closure(int x, int y) : m_x(x), m_y(y) {}
        virtual int operator()(int i) const { cout << m_x + m_y*i << "\t"; return (m_x - m_y) * i; }
    };

    // need a const reference here, to bind to a temporary
    const my_unary_functor<int,int>& closure_1_5 = my_unary_functor<int,int>(closure(1, 5))
    some_templated_function( collection, closure_1_5 );
}

Yes you can, but you'll have to implement one or more virtual methods declared in an interface.

template<typename Arg, typename Result>
struct my_unary_function
{
    virtual Result operator()(Arg) = 0;
};

template<typename Arg, typename Result>
struct my_unary_functor
{
    my_unary_function<Arg, Result> m_closure;
    my_unary_functor(my_unary_function<Arg, Result> closure) : m_closure(closure) {}
    Result operator()(Arg a) { return m_closure(a); }
};

template<typename T, TFunctor>
void some_templated_function( std::vector<T> items, TFunctor actor );

Then you can define and use a local closure:

void f()
{
    std::vector<int> collection;

    struct closure : my_unary_function<int, int>
    {
        int m_x, m_y;
        closure(int x, int y) : m_x(x), m_y(y) {}
        virtual int operator()(int i) const { cout << m_x + m_y*i << "\t"; return (m_x - m_y) * i; }
    };

    some_templated_function( collection, my_unary_functor<int,int>(closure(1, 5)) );
}

Credit to @Omnifarious for this improvement (my_unary_functor not needed):

void f()
{
    std::vector<int> collection;

    struct closure : my_unary_function<int, int>
    {
        int m_x, m_y;
        closure(int x, int y) : m_x(x), m_y(y) {}
        virtual int operator()(int i) const { cout << m_x + m_y*i << "\t"; return (m_x - m_y) * i; }
    };

    // need a const reference here, to bind to a temporary
    const my_unary_functor<int,int>& closure_1_5 = my_unary_functor<int,int>(closure(1, 5))
    some_templated_function( collection, closure_1_5 );
}
温柔戏命师 2024-11-09 02:59:40

如果这在 C++03 中可行,为什么 C++0x 会引入 lambda? lambda 存在是有原因的,因为绑定和所有其他 C++03 解决方案都很糟糕。

If this was doable in C++03, why would C++0x have introduced lambdas? There's a reason lambdas exist, and it's because binding and all the other C++03 solutions suck hideously.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文