2012-01-03 14 views
12

ラムダ関数の最初のパラメータ型を取得する方法はありますか?ラムダパラメータ型を取得

代わりに:私は希望

template<typename T> 
struct base 
{ 
    virtual bool operator()(T) = 0; 
} 

template<typename F, typename T> 
struct filter : public base<T> 
{ 
    virtual bool operator()(T) override {return /*...*/ } 
}; 

template<typename T, typename F> 
filter<T> make_filter(F func) 
{ 
     return filter<F, T>(std::move(func)); 
} 

auto f = make_filter<int>([](int n){return n % 2 == 0;}); 

template<typename F> 
struct filter : public base<typename param1<F>::type> 
{ 
    bool operator()(typename param1<F>::type){return /*...*/ } 
}; 

template<typename F> 
filter<F> make_filter(F func) 
{ 
     return filter<F>(std::move(func)); 
} 

auto f = make_filter([](int n){return n % 2 == 0;}); 

XEOの回答に基づいて、これは私がVS2010で働いて得たものである:

template<typename FPtr> 
struct arg1_traits_impl; 

template<typename R, typename C, typename A1> 
struct arg1_traits_impl<R (C::*)(A1)>{typedef A1 arg1_type;}; 

template<typename R, typename C, typename A1> 
struct arg1_traits_impl<R (C::*)(A1) const>{typedef A1 arg1_type;}; 

template<typename T> 
typename arg1_traits_impl<T>::arg1_type arg1_type_helper(T); 

template<typename F> 
struct filter : public base<typename std::decay<decltype(detail::arg1_type_helper(&F::operator()))>::type> 
{ 
    bool operator()(typename std::decay<decltype(detail::arg1_type_helper(&F::operator()))>::type){return /*...*/ } 
}; 

template<typename T, typename F> 
filter<F> make_filter(F func) 
{ 
     return filter<F>(std::move(func)); 
} 

私が単純化しようとしましたコードは、しかし、任意の試みはそれを破るようだ。

+0

が、しかし、VS2010は' first_argument_type'をimplemenetしていないようです。 – ronag

+0

複雑。 *非常に*複雑な、特にvariadicテンプレートとVS2010なし。関数ポインタの実際の型をそのコンポーネントに分割し、 'function_traits :: param1_type'などを使用する、ある種の関数型が必要になります。 VS2010はそのコードに問題がありますが、私が私の質問を見つけることができるかどうかを見てみましょう... – Xeo

+0

'std :: function 'は 'F'がラムダ型で署名ではないので使用できません'bool(int)'のように。 – Xeo

答えて

8

最も簡単オプションはちょうどoperator()テンプレート自体を作るために次のようになります。

template<typename F> 
struct filter 
{ 
    template<class Arg> 
    void operator(Arg&& arg){ 
     // use std::forward<Arg>(arg) to call the stored function 
    } 
}; 

template<typename F> 
filter<F> make_filter(F func) 
{ 
     return filter<F>(std::move(func)); 
} 

auto f = make_filter([](int n){return n % 2 == 0;}); 

理論的、次のコードは、だけを動作するはずです。それはGCCでどのように見えるかの

#include <iostream> 
#include <typeinfo> 

template<class FPtr> 
struct function_traits; 

template<class T, class C> 
struct function_traits<T (C::*)> 
{ 
    typedef T type; 
}; 

template<class F> 
void bar(F f){ 
    typedef typename function_traits< 
     decltype(&F::operator())>::type signature; 
    std::cout << typeid(signature).name(); 
} 

int main(){ 
    bar([](int n){ return n % 2 == 0; }); 
} 

Hereの例:しかし、それはバグMSVC10おかげでありません。しかし、MSVC10は単にコードをコンパイルしません。詳細については、this question of mineを参照してください。基本的に、MSVC10はdecltype(&F::operator())を依存型として扱いません。ここでchat discussionに考案された回避策です:私は `のstd ::のfuction :: first_argument_type`といくつかのトリックを見ていた

#include <iostream> 
#include <typeinfo> 
#include <type_traits> 

template<class FPtr> 
struct function_traits; 

template<class R, class C, class A1> 
struct function_traits<R (C::*)(A1)> 
{ // non-const specialization 
    typedef A1 arg_type; 
    typedef R result_type; 
    typedef R type(A1); 
}; 

template<class R, class C, class A1> 
struct function_traits<R (C::*)(A1) const> 
{ // const specialization 
    typedef A1 arg_type; 
    typedef R result_type; 
    typedef R type(A1); 
}; 

template<class T> 
typename function_traits<T>::type* bar_helper(T); 

template<class F> 
void bar(F f){ 
    typedef decltype(bar_helper(&F::operator())) fptr; 
    typedef typename std::remove_pointer<fptr>::type signature; 
    std::cout << typeid(signature).name(); 
} 

int main(){ 
    bar([](int n){ return n % 2 == 0; }); 
} 
+0

素晴らしい!しかし、filter :: operator()が仮想の場合はどうでしょうか? – ronag

+0

@ronag:問題があります。 :|クラス自体が関数/関数型にテンプレート化されているのであれば、なぜ 'virtual'にする必要がありますか? – Xeo

+0

これは簡単な例で、私の実際のコードフィルターには基本クラスがあります。 – ronag

関連する問題