最近我問了一個關于我的一些代碼的問題,這些代碼導致我的編譯器耗盡了堆空間。此代碼包含一個遞回模板函式,該函式被傳遞給一個 lambda 函式。模板函式的每個實體化都導致(通過遞回呼叫)使用它的 lambda 函式引數對同一模板函式進行另一個實體化。有人解釋說,lambda 函式的每個實體化都會產生一個唯一的型別,因此會導致實體化的無限回圈,并且編譯器會耗盡堆。請注意,程式的邏輯是在運行時不會出現無限回圈。
這是代碼示例,此代碼無法在任何主要編譯器上編譯。這段代碼是我真實代碼的大幅縮減版本,僅用于說明目的。
struct Null
{
template <typename SK>
static int match(int n, SK sk)
{
return 0;
}
};
template <typename T>
struct Repetition
{
template <typename SK>
static int match(int n, SK sk)
{
return T::match(0, [n]() { return match(0, [n](){ return n; }); });
}
};
int main()
{
using Test = Repetition<Null>;
Test::match(0, [](){ return 0; });
}
當解釋這一點時,我突然想到我可以通過使用仿函式而不是 lambda 函式來打破無限回圈,因為仿函式的每個實體化都不是唯一的型別。這是代碼,編譯得很好
struct Null
{
template <typename SK>
static int match(int n, SK sk)
{
return 0;
}
};
template <typename T>
struct Repetition
{
template <typename SK>
static int match(int n, SK sk)
{
return T::match(0, [n]() { return match(0, RepetitionSK<T>(n)); });
}
};
template <typename T>
struct RepetitionSK
{
RepetitionSK(int n) : n(n) {}
int operator()() { return n; }
int n;
};
int main()
{
using Test = Repetition<Null>;
Test::match(0, [](){ return 0; });
}
EDIT [=] 捕獲已被更明確的 [n] 取代
我的問題是,為什么 lambda 函式會這樣?中的 lambda 函式Repetition::match不SK以任何方式依賴模板引數。讓 lambda 函式的每個實體化都產生唯一型別有什么好處?
另一個問題,是否可以僅使用 lambda 函式而不使用仿函式或其他輔助類來撰寫此代碼?
uj5u.com熱心網友回復:
通過考慮相反的情況,這個問題更容易回答。如果它不是真的,那么一些 lambda 將具有相同的型別。此外,標準應該說明哪些 lambda 具有相同的型別,哪些 lambda 具有不同的型別。
請注意,“型別”不僅僅意味著operator(). Lambda 有真實的型別,例如他們有一個sizeof(必須包括捕獲的狀態)。
出于這個原因,您不能只根據標記來定義型別;令牌T可能相同,但含義因實體而異。
這個想法并不完全是獨一無二的。非行內函式也是唯一的,即使它們包含完全相同的標記(但函式型別將相同 - 對應關系不準確。并且函式沒有 a sizeof)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/488656.html
