![](/img/trans.png)
[英]C++11 lambda expression - Capture vs Argument Passing
[英]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.