Lambda函数作为基类 [英] Lambda functions as base classes

查看:119
本文介绍了Lambda函数作为基类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Lambdas进行游戏我发现了一个我不能完全理解的有趣的行为。



假设我有一个 struct Overload 来源于2个模板参数,并且有一个使用F1 :: operator(); 子句。



现在如果我从两个函数派生我只能访问F1的操作符()(如我所料)



如果我从两个Lambda函数派生,这不再。真:我可以从F2访问操作()太

 的#include<&iostream的GT; 

//我使用g ++编译(GCC)4.7.2 20121109(红帽4.7.2-8)
//
// g ++的-Wall -std = C + +11 -g main.cc
// g ++ -Wall -std = c ++ 11 -DFUNCTOR -g main.cc
//
//或clang clang version 3.3(标签/ RELEASE_33 / rc2)
//
// clang ++ -Wall -std = c ++ 11 -g main.cc
// clang ++ -Wall -std = c ++ 11 -DFUNCTOR - g main.cc
//
//在Linux上localhost.localdomain 3.9.6-200.fc18.i686#1 SMP Thu Jun 13
// 19:29:40 UTC 2013 i686 i686 i386 i386 GNU / Linux盒


struct Functor1
{
void operator()(){std :: cout< Functor1 ::运算符()()\\\
; }
};

结构Functor2
{
void运算符()(INT){性病::法院LT&;< Functor2 ::运算符()(INT)\\\
}
};

:模板LT; typename的F1,F2 typename的GT&;
struct Overload:public F1,public F2
{
Overload()
:F1()
,F2(){}

超载(F1 X1,X2 F2)
:F1(X1)
,F2(X2){}使用F1 ::运算

();
};

:模板LT; typename的F1,F2 typename的GT&;
auto get(F1 x1,F2 x2) - >过载< F1,F2>
{
return Overload< F1,F2>(x1,x2);
}


int main(int argc,char * argv [])
{
auto f = get(Functor1(),Functor2 );

f();
#ifdef FUNCTOR
f(2); // this one not work IMHO correctly
#endif

auto f1 = get(
[](){std :: cout< operator()()\\\
;},
[](int){std :: cout<lambda2 :: operator()(int)\\\
;}
);
f1();
f1(2); // this one work but I do not know why


return 0;
}

标准规定:


lambda表达式的类型(也是闭包对象的类型)
是一个唯一的未命名非联合类类型

$ b $



我不能解释为什么会这样:任何人都可以 c 除了运算符() c> ,由lambda定义的类可以(在正确的情况下)提供到指向函数的指针的转换。



如果你添加一个捕获:

  auto f1 = get(
[](){std :: cout<lambda1 :: operator ;},
[i](int){std :: cout<lambda2 :: operator()(int)\\\
;}
);
f1();
f1(2);

...转换为指向函数的指针

  trash9.cpp:

在函数'int main(int,char **)':
trash9.cpp:49:9:error:没有匹配的调用'(Overload< main(int,char **)::& ()>,main(int,char **)::< lambda(int)>)(int)'
trash9.cpp:14:8:note:candidate is:
trash9.cpp:45:23:note:main(int,char **)::< lambda()
trash9.cpp:45:23:注意:候选人期望有0个参数,1个提供


Playing around with Lambdas I found an interesting behaviour that I do not fully understand.

Supose I have a struct Overload that derives from 2 template parameters, and has a using F1::operator(); clause.

Now if I derive from two functors I can only access the operator() of F1 (as I would expect)

If I derive from two Lambda Functions this is no longer true: I can access the operator() from F2 too.

#include <iostream>

// I compiled with g++ (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8)
//
// g++ -Wall -std=c++11 -g main.cc
// g++ -Wall -std=c++11 -DFUNCTOR -g main.cc
// 
// or clang clang version 3.3 (tags/RELEASE_33/rc2)
// 
// clang++ -Wall -std=c++11 -g main.cc
// clang++ -Wall -std=c++11 -DFUNCTOR -g main.cc
// 
// on a Linux localhost.localdomain 3.9.6-200.fc18.i686 #1 SMP Thu Jun 13 
// 19:29:40 UTC 2013 i686 i686 i386 GNU/Linux box


struct Functor1
{
    void operator()() { std::cout << "Functor1::operator()()\n"; }
};

struct Functor2
{
    void operator()(int) { std::cout << "Functor2::operator()(int)\n"; }
};

template <typename F1, typename F2>
struct Overload : public F1, public F2
{
    Overload()
        : F1()
        , F2() {}

    Overload(F1 x1, F2 x2)
        : F1(x1)
        , F2(x2) {}

    using F1::operator(); 
};

template <typename F1, typename F2>
auto get(F1 x1, F2 x2) -> Overload<F1, F2>
{
   return Overload<F1, F2>(x1, x2);
}


int main(int argc, char *argv[])
{
    auto f = get(Functor1(), Functor2());

    f();
#ifdef FUNCTOR
    f(2); // this one doesn't work IMHO correctly
#endif

    auto f1 = get(
                  []() { std::cout << "lambda1::operator()()\n"; },
                  [](int) { std::cout << "lambda2::operator()(int)\n"; }
                  );
    f1();
    f1(2); // this one works but I don't know why


  return 0;
}

The standard states that:

The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non- union class type

So every Lambda's types should be unique.

I cannot explain why this is so: can anyone shed some light on this please?

解决方案

In addition to operator(), a the class defined by a lambda can (under the right circumstances) provide a conversion to a pointer to function. The circumstance (or at least the primary one) is that the lambda can't capture anything.

If you add a capture:

auto f1 = get(
              []() { std::cout << "lambda1::operator()()\n"; },
              [i](int) { std::cout << "lambda2::operator()(int)\n"; }
              );
f1();
f1(2);

...the conversion to pointer to function is no longer provided, so trying to compile the code above gives the error you probably expected all along:

trash9.cpp: In function 'int main(int, char**)':
trash9.cpp:49:9: error: no match for call to '(Overload<main(int, char**)::<lambda()>, main(int, char**)::<lambda(int)> >) (int)'
trash9.cpp:14:8: note: candidate is:
trash9.cpp:45:23: note: main(int, char**)::<lambda()>
trash9.cpp:45:23: note:   candidate expects 0 arguments, 1 provided

这篇关于Lambda函数作为基类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆