簡體   English   中英

將lambda表達式傳遞給lambda參數c ++ 11

[英]Pass lambda expression to lambda argument c++11

我想做這樣的事情:

int main()
{
    auto f = [/*some variables*/](/*take lambda function*/)
    {/*something with lambda function*/};

    f([/*other variables*/](/*variables to be decided by f()*/)
    {/*something with variables*/});
}

我知道可以將lambda傳遞給函數,也可以傳遞給lambda。 以下作品:

int main()
{
    int x=0;
    int y=0;
    auto f = [x,y](double (func)(int)) -> double
    {func(0); return 0.0;};

    f([](int i) -> double
    {return 0.0;});
}

但以下不起作用(只要我將范圍變量更改為添加[x])

int main()
{
    int x=0;
    int y=0;
    auto f = [x,y](double (func)(int)) -> double
    {func(0); return 0.0;}

    f([x](int i) -> double    //[x] does not work
    {return 0.0;});
}

這給出了錯誤:

error: function "lambda [](double (*)(int))->double::operator()" cannot be called with the given argument list
        argument types are: (lambda [](int)->double)
        object type is: lambda [](double (*)(int))->double

誰會想到如何解決這個問題,或者解決這個問題? 我正在使用帶有std = c ++ 11的intel編譯器icpc(ICC)13.1.2

謝謝

關於你的問題,有幾點需要澄清。 第一個是什么是lambda?

lambda表達式是一個簡單的表達式,編譯器將從中生成一個無法命名的唯一類型,同時它將生成該類型的實例。 當你寫: [](int i) { std::cout << i; } [](int i) { std::cout << i; }編譯器會為你生成一個類型大致是:

struct __lambda_unique_name {
   void operator()(int i) const { std::cout << i; }
};

如您所見,它不是一個函數,而是一個將operator()實現為const成員函數的類型。 如果lambda進行了任何捕獲,編譯器將生成捕獲值/引用的代碼。

作為一個角落案例,對於像上面這樣沒有捕獲狀態的lambdas,語言允許從lambda類型轉換為指向function的指針(具有operator()減號(減去this部分),所以上面的lambda可以隱式轉換為函數獲取int並且不返回任何內容的指針:

void (*f)(int) = [](int i) { std::cout << i; }

現在已經說明了基礎知識,在你的代碼中你有這個lambda:

auto f = [x,y](double (func)(int)) -> double {func(0); return 0.0;};

函數參數的規則(也適用於lambdas)確定參數不能是函數類型,因此lambda的參數衰減為指向函數的指針(與數組類型的參數衰減為指針的方式相同)類型):

auto f = [x,y](double (*func)(int)) -> double {func(0); return 0.0;};

稍后您將嘗試傳遞一個以捕獲為參數的lambda。 因為存在捕獲,所以特殊規則不適用,並且lambda不能轉換為指向函數的指針,從而產生您看到的編譯器錯誤。

在當前標准中,您可以采用兩種方式之一。 您可以使用type-erasure從簽名中刪除可調用實體的確切類型:

auto f = [x,y](std::function<double(int)> func) -> double {func(0); return 0.0;};

因為std::function<double(int)>可以使用任何具有適當簽名的可調用實體進行初始化,所以這將接受下面代碼中的lambdas,代價是類型擦除,通常意味着動態分配和動態分派。

或者,您可以刪除語法糖並手動滾動第一個lambda等效項,但將其設為通用。 在這種情況下,lambda很簡單,這可能是一個有效的選項:

struct mylambda {
   template <typename F>
   double operator()(F fn) const {
      fn(0); return 0.0;
   }
} f;
// then use the non-lambda as you tried:
f([x](int i) -> double {return 0.0;});

最后,如果你足夠耐心,你可以等待C ++ 14,其中(很可能,它還沒有被批准)將支持多態lambda ,這簡化了上述類的創建:

auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to 'mylambda' above

嘗試使用std :: function:

#include <functional>
int main()
{
    int x=0;
    int y=0;
    auto f = [x,y](std::function<double(int)> func) -> double
             {func(0); return 0.0;};

    f([x](int i) -> double {return 0.0;});
}

你可能不得不像在黑暗時代那樣咬住子彈並實現自己的仿函數:

struct F {
    int x;
    int y;

    F(int x_, int y_) : x(x_), y(y_) {}

    template <typename G>
    double operator() (G&& g) const {
        g(0);
        return 0.0;
    }
};

#include <iostream>

int main()
{
    int x = 0;
    int y = 0;
    auto f = F(x, y);

    f([x](int i){return 0.0;});
    f([](int i){std::cout << i << std::endl;});
}

這應該讓你繼續,直到你的編譯器支持C ++ 14泛型lambda。

如果您事先知道lambda的類型,可以嘗試類似下面的內容,例如:

int main()
{
    int x = 0, y = 0;

    auto f = [x]( int i )->double {
        return (double)x;
    };

    auto f2 = [x,y]( decltype(f) func )->double {
        return func( 0 );
    };

    f2( f );

    return 0;
}

或者您可以使用<functional>庫來獲得更通用的解決方案,例如:

auto f = [x,y]( std::function<double(int)> func ) { /* Do stuff */ };

你可以知道一個捕獲lambda,但這個解決方案有其局限性:

#include <new>

#include <utility>

namespace
{

template <typename F, int I, typename L, typename R, typename ...A>
inline F cify(L&& l, R (*)(A...) noexcept(noexcept(
  std::declval<F>()(std::declval<A>()...))))
{
  static L l_(std::forward<L>(l));
  static bool full;

  if (full)
  {
    l_.~L();

    new (static_cast<void*>(&l_)) L(std::forward<L>(l));
  }
  else
  {
    full = true;
  }

  return [](A... args) noexcept(noexcept(
      std::declval<F>()(std::forward<A>(args)...))) -> R
    {
      return l_(std::forward<A>(args)...);
    };
}

}

template <typename F, int I = 0, typename L>
inline F cify(L&& l)
{
  return cify<F, I>(std::forward<L>(l), F());
}


int main()
{
    int x=0;
    int y=0;
    auto f = [x,y](double (func)(int)) -> double
    {func(0); return 0.0;};

    f(cify<double(*)(int i)>([x](int i) -> double    //works now
    {return 0.0;}));
}

單擊以查看工作示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM