从通用lambda - clang和gcc调用`this`成员函数 [英] Calling `this` member function from generic lambda - clang vs gcc

查看:167
本文介绍了从通用lambda - clang和gcc调用`this`成员函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:传递捕获的通用lambda (到模板函数),并调用成员函数这个没有明确的 this-> 不能在gcc上编译。如果lambda不是通用的,或者如果lambda没有传递给任何其他函数,但是调用到位,它编译具有显式 this-> 。 Clang在所有情况下都很酷。



另一轮 clang vs gcc 的时间。谁是正确的?



Wandbox示例






  template< typename TF> 
void call(TF&& f)
{
f(1);
}

struct示例
{
void foo(int){}

void bar()
{
call([this](auto x){foo(x);});
}
};

int main()
{
示例{}。
return 0;
}






    li> bar() = call([this](auto x){foo(x);});


    • clang ++ 3.6+ 编译

    • g ++ 5.2+


      错误:无法调用成员函数'void Example :: foo(int)'无对象
      call ](auto x){foo(x);});`










  • 使用 bar() = call([this](auto x){this-> foo(x);});


    • clang ++ 3.6+ 编译

    • g ++ 5.2+ 编译 li>






    • 使用 bar / code> = call([this](int x){foo(x);});


      • clang ++ 3.6+ 编译

      • g ++ 5.2+ / ul>







      • 使用 bar() = [this](auto x){foo(x); }(1);


        • clang ++ 3.6+ 编译

        • g ++ 5.2+ 编译




      <

      为什么 this-> 仅在通用lambda的情况下才需要?


      $如果未将lambda传递给 call ,为什么 this->



      谁不符合标准?

      解决方案

      是一个gcc bug。来自[expr.prim.lambda]:


      产生函数调用运算符
      function-body (8.4),但是为了查找名称(3.4),确定 this (9.3.2)并将 id-expressions
      转换为类成员访问表达式中的非静态类成员 * this)(9.3.1),在 lambda-expression 的上下文中考虑复合语句 [示例:

        struct S1 {
      int x,y;
      int operator()(int);
      void f(){
      [=]() - > int {
      return operator()(this-> x + y);
      //相当于S1 :: operator()(this-> x +(* this).y)
      //这是类型S1 *
      }
      }
      };

      -end example]


      < blockquote>

      由于在您的示例中捕获 this ,名称查找应包括 / code>,因此应该找到 Example :: foo 。执行的查找与如果 foo(x)出现在 lambda-expression 本身的上下文中会发生的情况相同,也就是说如果代码看起来像:

        void bar()
      {
      foo(x); //清楚例子:: foo(x);
      }

      至少这个bug有一个非常简单的解决方法,如问题所示:just do this-> foo(x);


      Issue: passing a generic lambda (to a template function) that captures this and calls a member function of this without an explicit this-> does not compile on gcc. If the lambda is not generic, or if the lambda is not passed to any other function but called in place, it compiles withoit an explicit this->. Clang is cool with the code in all situations.

      Time for another round of clang vs gcc. Who's right?

      Wandbox example


      template<typename TF>
      void call(TF&& f)
      {
          f(1);   
      }
      
      struct Example
      {        
          void foo(int){ }
      
          void bar()
          {
              call([this](auto x){ foo(x); });
          }
      };
      
      int main()
      {
          Example{}.bar();
          return 0;
      }
      


      • With bar() = call([this](auto x){ foo(x); });
        • clang++ 3.6+ compiles.
        • g++ 5.2+ does not compile.

          error: cannot call member function 'void Example::foo(int)' without object call([this](auto x){ foo(x); });`


      • With bar() = call([this](auto x){ this->foo(x); });
        • clang++ 3.6+ compiles.
        • g++ 5.2+ compiles.

      • With bar() = call([this](int x){ foo(x); });
        • clang++ 3.6+ compiles.
        • g++ 5.2+ compiles.

      • With bar() = [this](auto x){ foo(x); }(1);
        • clang++ 3.6+ compiles.
        • g++ 5.2+ compiles.

      Why is the this-> necessary only in the case of a generic lambda?

      Why is the this-> not necessary if the lambda isn't passed to call?

      Who is being non standard-compliant?

      解决方案

      This is a gcc bug. From [expr.prim.lambda]:

      The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id-expressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement is considered in the context of the lambda-expression. [ Example:

      struct S1 {
          int x, y;
          int operator()(int);
          void f() {
              [=]()->int {
                  return operator()(this->x + y); 
                      // equivalent to S1::operator()(this->x + (*this).y)
                      // this has type S1*
              };
          }
      };
      

      —end example ]

      Since in your example you capture this, the name lookup should include class members of Example, which should therefore find Example::foo. The lookup performed is identical to what would happen if foo(x) appeared in the context of the lambda-expression itself, that is if the code looked like:

      void bar()
      {
          foo(x); // clearly Example::foo(x);
      }
      

      At least this bug has a very simple workaround as indicated in the question: just do this->foo(x);.

      这篇关于从通用lambda - clang和gcc调用`this`成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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