問題描述
可以將 lambda 表達式用作作為類模板參數嗎?(請注意,這是一個與 this one 截然不同的問題,后者詢問是否lambda 表達式本身可以被模板化.)
Can lambda expressions be used as class template parameters? (Note this is a very different question than this one, which asks if a lambda expression itself can be templated.)
我在問你是否可以這樣做:
I'm asking if you can do something like:
template <class Functor>
struct Foo { };
// ...
Foo<decltype([]()->void { })> foo;
這在以下情況下很有用,例如,類模板具有各種參數,例如 equal_to
或其他東西,這些參數通常被實現為單行函子.例如,假設我想實例化一個哈希表,它使用我自己的自定義相等比較函數.我希望能夠這樣說:
This would be useful in cases where, for example, a class template has various parameters like equal_to
or something, which are usually implemented as one-liner functors. For example, suppose I want to instantiate a hash table which uses my own custom equality comparison function. I'd like to be able to say something like:
typedef std::unordered_map<
std::string,
std::string,
std::hash<std::string>,
decltype([](const std::string& s1, const std::string& s2)->bool
{ /* Custom implementation of equal_to */ })
> map_type;
但是我在 GCC 4.4 和 4.6 上測試了這個,它不起作用,顯然是因為由 lambda 表達式創建的匿名類型沒有默認構造函數.(我記得 boost::bind
也有類似的問題.)標準草案是否有某些原因不允許這樣做,或者我錯了,它被允許但 GCC 只是在他們的實施中落后?
But I tested this on GCC 4.4 and 4.6, and it doesn't work, apparently because the anonymous type created by a lambda expression doesn't have a default constructor. (I recall a similar issue with boost::bind
.) Is there some reason the draft standard doesn't allow this, or am I wrong and it is allowed but GCC is just behind in their implementation?
推薦答案
從 C++20 開始,這個答案現在已經過時了.C++20 在未評估的上下文中引入了無狀態 lambdas1:
As of C++20, this answer is now outdated. C++20 introduces stateless lambdas in unevaluated contexts1:
此限制最初旨在防止 lambda 出現在簽名中,因為 lambda 需要具有唯一類型,因此這會打開一罐蠕蟲進行重整.然而,限制比它需要的要強得多,沒有它確實可以達到同樣的效果
This restriction was originally designed to prevent lambdas from appearing in signatures, which would have opened a can of worm for mangling because lambdas are required to have unique types. However, the restriction is much stronger than it needs to be, and it is indeed possible to achieve the same effect without it
一些限制仍然存在(例如 lambdas 仍然不能出現在函數簽名上),但所描述的用例現在完全有效并且不再需要聲明變量.
Some restrictions are still in place (e.g. lambdas still can't appear on function signatures), but the described usecase is now completely valid and the declaration of a variable is no longer necessary.
我在問你是否可以這樣做:
I'm asking if you can do something like:
Foo<decltype([]()->void { })> foo;
不,您不能,因為 lambda 表達式不應出現在未計算的上下文中(例如 decltype
和 sizeof
等).C++0x FDIS, 5.1.2 [expr.prim.lambda] p2
No you can't, because lambda expressions shall not appear in an unevaluated context (such as decltype
and sizeof
, amongst others).
C++0x FDIS, 5.1.2 [expr.prim.lambda] p2
對 lambda 表達式的求值產生一個 prvalue 臨時值 (12.2).這個臨時被稱為閉包對象.lambda 表達式不得出現在未計算的操作數中(第 5 條).[注:A閉包對象的行為就像一個函數對象(20.8).——尾注](強調我的)
The evaluation of a lambda-expression results in a prvalue temporary (12.2). This temporary is called the closure object. A lambda-expression shall not appear in an unevaluated operand (Clause 5). [ Note: A closure object behaves like a function object (20.8).—end note ] (emphasis mine)
您需要首先創建一個特定的 lambda,然后對其使用 decltype:
You would need to first create a specific lambda and then use decltype on that:
auto my_comp = [](const std::string& left, const std::string& right) -> bool {
// whatever
}
typedef std::unordered_map<
std::string,
std::string,
std::hash<std::string>,
decltype(my_comp)
> map_type;
那是因為每個 lambda 派生的閉包對象都可以有完全不同的類型,畢竟它們就像匿名函數.
That is because each lambda-derived closure object could have a completely different type, they're like anonymous functions after all.
這篇關于Lambda 表達式作為類模板參數的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!