一般的なラムダ関数が与えられたときに非自動パラメーターの型を取得するコードをいくつか書きました。以下のコードでわかるように、一般的なラムダを使用して connect 関数を呼び出し、auto パラメーターに引数を提供するという考え方です (私のユース ケースでは常に先頭に配置されます)。したがって、以下のコードでの私の目標は、2 番目のパラメーターが float 型であることを検出することでした。
コードは clang 3.8 では正常に動作しますが、gcc 6.1.1 ではコンパイルされません。これは gcc のバグなのか、それとも有効な C++ コードではないのか疑問に思っていました。汎用ラムダがテンプレート化された operator() 関数で実装されていると仮定できますか、それともこれはコンパイラ固有のものですか?
template <typename Functor, typename... AllArgs, typename... ProvidedArgs>
void findArgTypes(void(Functor::*)(AllArgs...) const, Functor, ProvidedArgs...)
{
// AllArgs == int, float
// ProvidedArgs == int
}
template <typename Func, typename... ProvidedArgs>
void connect(Func func, ProvidedArgs... providedArgs)
{
findArgTypes(&Func::template operator()<ProvidedArgs...>, func, providedArgs...);
}
int main()
{
int tmp = 0;
connect([&](auto, float){ ++tmp; }, 0);
}
gcc が与えるエラーは次のとおりです。
main.cpp: In instantiation of ‘void connect(Func, ProvidedArgs ...) [with Func = main()::<lambda(auto:1, float)>; ProvidedArgs = {int}]’:
main.cpp:16:33: required from here
main.cpp:11:17: error: no matches converting function ‘operator()’ to type ‘void (struct main()::<lambda(auto:1, float)>::*)() const’
findArgTypes(&Func::template operator()<ProvidedArgs...>, func, providedArgs...);
~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:16:27: note: candidate is: template<class auto:1> main()::<lambda(auto:1, float)>
connect([](auto, float){}, 0);
^
const
findArgTypesの を削除すると、同じ結果が得られます。
次のコードを使用すると、両方のコンパイラで機能します。
struct Foo
{
template <typename T>
void operator()(T, float) const {}
};
int main()
{
Foo f;
connect(f, 0);
}