Variable templates + generic lambdas for std::map
C++14で導入される予定の変数テンプレートですが、ラムダ式でその変数をキャプチャするときには注意が必要です。
まだインスタンス化されていない型の変数テンプレートは、ラムダ式でキャプチャしても使用できません。
以下のプログラムでは、ラムダ式の参照キャプチャで変数テンプレートstorage
をキャプチャすることを意図していますが、ラムダ式を定義した時点でstorage
はどの型に対してもインスタンス化されていないため、キャプチャされません。
Clang 3.4では、これはリンクエラーになります。
#include <map> #include <string> template <typename T> std::map<int, T> storage; void some_func() { auto store = [&](auto pair) { storage<decltype(pair.second)>.insert(pair); }; store(std::pair<int, int>(0, 1)); store(std::pair<int, std::string>(1, "Hello!")); store(std::pair<int, int>(2, 3)); } int main() { }
リンクエラーのメッセージ(読みやすいように整形してます):
/tmp/prog-d14554.o: In function `some_func()::lambda(pair<int, int>)': prog.cc: undefined reference to `storage<int>' /tmp/prog-d14554.o: In function `some_func()::lambda(pair<int, string>)': prog.cc: undefined reference to `storage<string>' clang: error: linker command failed with exit code 1 (use -v to see invocation)
変数テンプレートをラムダ式でキャプチャする場合は、ラムダ式で使用するテンプレート引数の型で、事前にインスタンス化しておく必要があります:
#include <map> #include <string> template <typename T> std::map<int, T> storage; template <> std::map<int, int> storage<int>; template <> std::map<int, std::string> storage<std::string>; void some_func() { auto store = [&](auto pair) { storage<decltype(pair.second)>.insert(pair); }; store(std::pair<int, int>(0, 1)); // OK store(std::pair<int, std::string>(1, "Hello!")); // OK store(std::pair<int, int>(2, 3)); // OK } int main() { }