C ++ 11では、ラムダ関数をテンプレート化する方法はありますか?それともテンプレート化するには本質的に具体的すぎますか?
代わりに、古典的なテンプレートクラス/ファンクタを定義できることを理解していますが、問題はより似ています:言語はテンプレートのラムダ関数を許可しますか?
C ++ 11では、ラムダ関数をテンプレート化する方法はありますか?それともテンプレート化するには本質的に具体的すぎますか?
代わりに、古典的なテンプレートクラス/ファンクタを定義できることを理解していますが、問題はより似ています:言語はテンプレートのラムダ関数を許可しますか?
回答:
UPDATE 2018:C ++ 20には、テンプレート化および概念化されたラムダが付属します。この機能はすでに標準ドラフトに統合されています。
UPDATE 2014:C ++ 14は今年リリースされ、現在、この例と同じ構文の多形ラムダを提供しています。一部の主要なコンパイラはすでにそれを実装しています。
現状では(C ++ 11では)残念ながら違います。ポリモーフィックラムダは、柔軟性とパワーの点で優れています。
彼らが単相性になった最初の理由は、概念のためでした。概念により、このコードの状況は困難になりました。
template <Constraint T>
void foo(T x)
{
auto bar = [](auto x){}; // imaginary syntax
}
制約付きテンプレートでは、他の制約付きテンプレートのみを呼び出すことができます。(それ以外の場合、制約はチェックできませんでした。)foo
呼び出すことができますbar(x)
か?ラムダにはどのような制約がありますか(結局のところ、そのパラメーターは単なるテンプレートです)?
コンセプトはこの種のものに取り組む準備ができていませんでした。late_check
(概念が呼び出されるまでチェックされなかった場合)などのようなものがさらに必要になります。単純にそれをすべて落とし、単相ラムダに固執するだけでした。
ただし、C ++ 0xから概念が削除されたため、多形ラムダは再び単純な命題になります。しかし、私はそれについての提案を見つけることができません。:(
C ++ 11ラムダは他の回答で述べられているようにテンプレート化できませんがdecltype()
、テンプレート化されたクラスまたは関数内でラムダを使用するときに役立つようです。
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void boring_template_fn(T t){
auto identity = [](decltype(t) t){ return t;};
std::cout << identity(t) << std::endl;
}
int main(int argc, char *argv[]) {
std::string s("My string");
boring_template_fn(s);
boring_template_fn(1024);
boring_template_fn(true);
}
プリント:
My string
1024
1
この方法はテンプレート化されたコードを扱うときに役立つことがわかりましたが、それでもラムダ自体をテンプレート化できないことを認識しています。
T
decltype(t)
この例ではの代わりにうまく機能します。
C ++ 11ではラムダ関数をテンプレート化できませんが、ISO C ++標準の次のバージョン(C ++ 14と呼ばれることが多い)では、この機能が導入されます。[ソース]
使用例:
auto get_container_size = [] (auto container) { return container.size(); };
構文ではキーワードをauto
使用しますが、auto
型の推定では型の推定の規則は使用されず、代わりにテンプレート引数の推定の規則が使用されます。一般的なラムダ式の提案(およびこれに対する更新)も参照してください。
auto
型の推論の規則は、template
関数の引数の推論の規則と同じになるように明確に定義されています。
これはどうですか?
template <class something>
inline std::function<void()> templateLamda() {
return [](){ std::cout << something.memberfunc() };
}
このようなコードを使用してテンプレートを生成し、コンパイラーが「ラッピング」関数を最適化するかどうか疑問に思いました。
ラムダテンプレートを許可するgcc拡張があります。
// create the widgets and set the label
base::for_each(_widgets, [] <typename Key_T, typename Widget_T>
(boost::fusion::pair<Key_T, Widget_T*>& pair) -> void {
pair.second = new Widget_T();
pair.second->set_label_str(Key_T::label);
}
);
どこ_widgets
でstd::tuple< fusion::pair<Key_T, Widget_T>... >
私はフラグversion 5.0.1
を使用してコンパイルしている最新のclangで遊んでおり-std=c++17
、ラムダの自動型パラメーターのいくつかの素晴らしいサポートがあります:
#include <iostream>
#include <vector>
#include <stdexcept>
int main() {
auto slice = [](auto input, int beg, int end) {
using T = decltype(input);
const auto size = input.size();
if (beg > size || end > size || beg < 0 || end < 0) {
throw std::out_of_range("beg/end must be between [0, input.size())");
}
if (beg > end) {
throw std::invalid_argument("beg must be less than end");
}
return T(input.begin() + beg, input.begin() + end);
};
auto v = std::vector<int> { 1,2,3,4,5 };
for (auto e : slice(v, 1, 4)) {
std::cout << e << " ";
}
std::cout << std::endl;
}
以下は、ランバを構造体でラップすることを含む1つのソリューションです。
template <typename T>
struct LamT
{
static void Go()
{
auto lam = []()
{
T var;
std::cout << "lam, type = " << typeid(var).name() << std::endl;
};
lam();
}
};
doを使用するには:
LamT<int>::Go();
LamT<char>::Go();
#This prints
lam, type = i
lam, type = c
これの主な問題(追加のタイピング以外に)は、この構造定義を別のメソッド内に埋め込むことができないか、または(gcc 4.9)を取得します。
error: a template declaration cannot appear at block scope
私もこれをやってみました:
template <typename T> using LamdaT = decltype(
[](void)
{
std::cout << "LambT type = " << typeid(T).name() << std::endl;
});
このように使用できることを願って:
LamdaT<int>();
LamdaT<char>();
しかし、コンパイラエラーが発生します。
error: lambda-expression in unevaluated context
したがって、これは機能しません...しかし、コンパイルできたとしても、「テンプレートを使用しているため」「目的のLamdaT」をファイルスコープに配置する必要があるため、用途が限られます。ラムダ。
なぜだれもこれを提案していない理由はわかりませんが、ラムダ関数を返すテンプレート関数を作成できます。以下は私の問題、私がこのページに来た理由を解決しました:
template <typename DATUM>
std::function<double(DATUM)> makeUnweighted() {
return [](DATUM datum){return 1.0;};
}
与えられたタイプの引数(例えばstd::string
)を取る関数が欲しいときはいつでも、
auto f = makeUnweighted<std::string>()
そして今f("any string")
戻る1.0
。
これが、「テンプレート化されたラムダ関数」の意味する例です。(この特定のケースは、データが何であれ、誰かがデータに重み付けしたくない場合に、自動的に不活性な重み付け関数を提供するために使用されます。)