c++ lambda 函數的 static 屬性是否無效?

嘗試用 c++ 實現 Y Combinator 時發現一個奇怪的情況,代碼如下

#include &
#include &
#include &
using namespace std;
int main()
{
auto F = [](auto f, int n)-&>int {if (n &< 1) return 1; else return n * f(n - 1); }; auto H = [](auto f, int n)-&>int {if (n &< 1) return 1; else return n + f(n - 1); }; auto Y = [](autof) { static auto fgen = [](auto self, int n)-&>int // 使用 static 的目的是避免棧解除後 fgen 引用錯誤,雖然實際上並不會出錯
{
return f([](int k)-&>int {return self(self, k); }, n);
};
return [](int k){return fgen(fgen, k);};
};

cout &<&< Y(F)(3) &<&< endl &<&< Y(H)(5); return 0; }

期望輸出6和120,實際上輸出的是6和16。

接下來我做了如下改動

auto Y = [](autof, int n)
{
static auto fgen = [](auto self, int n)-&>int
{
return f([](int k)-&>int {return self(self, k); }, n);
};
return fgen(fgen, n);
};

cout &<&< Y(F, 3) &<&< endl &<&< Y(H, 5);

依舊輸出6和16。

考慮到是不是 lambda 函數的特殊性,我又用可變參數模板試了下:

#include &
#include &
#include &
#include &
using namespace std;
template&
auto Y(FN f, ARGS... args) // 這個居然能匹配,很奇怪
{
static auto fgen = [](auto self, ARGS... args)-&>int
{
return f([](int k)-&>int {return self(self, k); }, args...);
};
return fgen(fgen, args...);
}
int main()
{
auto F = [](auto f, int n)-&>int {if (n &< 1) return 1; else return n * f(n - 1); }; auto H = [](auto f, int n)-&>int {if (n &< 1) return 1; else return n + f(n - 1); }; cout &<&< Y(F, 3) &<&< endl &<&< Y(H, 5); cout &<&< endl &<&< (typeid(F) == typeid(H)); return 0; }

輸出

6

16

0

這沒什麼說服力,畢竟F 和 H 類型並不一樣。但二者都是右值,看來是調用時生成的。

所以,lambda 函數內的 static 屬性是都沒有意義嗎?


正確答案:因為參數是auto,所以Y是一個模板函數,你傳入F和傳入H的時候分別特化了兩個版本,當然也就有兩個static fgen了。這沒有什麼奇怪的。


auto H = [](auto f, int n)-&>int {if (n &< 1) return 1; else return n + f(n - 1); };

你這個H看上去不是階乘而是sum啊


Y是表達式


自己回答一下。

搞了這麼個玩意兒。

#include &
#include &
#include &
#include &
#include &
using namespace std;

template&
auto YTmpl(FN f, ARGS... args)
{
static auto fgen = [](auto self, ARGS... args)-&>int
{
return f([](int k)-&>int {return self(self, k); }, args...);
};
return fgen(fgen, args...);
}
auto YLambda = [](autof, int n)
{
static auto fgen = [](auto self, int n)-&>int
{
return f([](int k)-&>int {return self(self, k); }, n);
};
return fgen(fgen, n);
};

#define YY(fn, ...)
YTmpl(decltype(test::Decode(test::decVal&(), ##__VA_ARGS__))::fn_t(fn), ##__VA_ARGS__)
#define YYY(fn, ...)
YLambda(decltype(test::Decode(test::decVal&(), ##__VA_ARGS__))::fn_t(fn), ##__VA_ARGS__)

namespace test {
template&
struct decode
{
typedef function&, ARGS...)&> fn_t;
};
template&
decode& Decode(RET, ARGS...)
{
decode& dec;
return dec;
}
template&
RET decVal() { RET val; return val; }
}

int main()
{
auto F = [](auto f, int n)-&>int {if (n &< 1) return 1; else return n * f(n - 1); }; auto H = [](auto f, int n)-&>int {if (n &< 1) return 1; else return n + f(n - 1); }; cout &<&< YY(F, 3) &<&< endl &<&< YY(H, 5) &<&< endl; cout &<&< YYY(H, 5) &<&< endl &<&< YYY(F, 3); return 0; }

輸出結果

7

16

120

6

還是實例化的問題,怨不得 lambda。


推薦閱讀:

哪些函數的增長速度能勝過指數函數?
如何理解logistic函數?
你見過的最污的函數圖像是什麼?
大家都用什麼軟體繪製函數圖像呢?
這個推導是正確的嗎?為什麼

TAG:函數 | CC | 遞歸 | Lambda表達式 |