2011-07-12 23 views
4

は、あなたがファンクタを持っていると仮定しますテンプレートで使用するために、(Functorメンバーの)関数シグネチャから引数型を取り出すことは可能ですか?

struct MyFunctor 
{ 
    bool operator()(int value) 
    { 
     return true; 
    } 
}; 

は、それはあなたのテンプレート内で使用する数子のメンバーの引数の型を取得することは可能ですか?以下は、この神秘的な機能を使用することである:

template < typename FunctorType > 
bool doIt(FunctorType functor, typename FunctorType::operator()::arg1 arg) 
{ 
    return functor(arg); 
} 

私の神話FunctorType::operator()::arg1の代わりとなる有効な構文はありますか?

+1

使用であるかもしれない同様の質問への答え:のhttp://のstackoverflowを。com/questions/6512019/can-we-get-the-lambda-argument/6512387#6512387関数シグネチャが与えられれば、その情報を抽出することは可能ですが、任意の関数オブジェクトを指定すると、 。 –

答えて

4

いいえありません。これを行う最もエレガントな方法は、ファンクタが引数型にtypedefを指定するか、traits-classを導入することです。後者は、テンプレートをファンクタや関数とともに使用する場合に便利です。

代わりに、あなただけの引数が2番目のテンプレートパラメータを入力することができます:

template < typename FunctorType, class ArgumentType > 
bool doIt(FunctorType functor, ArgumentType arg) 
{ 
    return functor(arg); 
} 

ArgumentTypeはファンクタで必要な型と一致しない場合、コンパイラはまだ文句を言うでしょう。

+0

boost :: functionは事実上同様のことをしなければなりませんか? – Catskul

+0

@Catskul: 'boost :: function'は2番目の例のように、引数のそれぞれに明示的なテンプレートパラメータとreturn型を持っています。 –

3

あなたは一種のC++ 0xの

template <typename... Args> 
struct Function { 
    typedef std :: tuple <Args...> args; 
    void call() (Args... args); 
} 

template <typename... Args> 
void do_it (Function<Args...>::args:: SOMETHING :: type t, Args... args) { 
    something (t) 
    Function <Args...> :: call (args...); 
} 
5

でそれを行うことができますが、項目はファンクタであることがわかっている場合、あなたはちょうどそのoperator()をつかむことができ、そのような:については

#include <iostream> 

template <unsigned Idx, typename... T> 
struct pick 
{ 
    static_assert(Idx < sizeof...(T), "cannot index past end of list"); 
}; 

template <typename T, typename... TRest> 
struct pick<0U, T, TRest...> 
{ 
    typedef T result; 
}; 

template <unsigned Idx, typename T, typename... TRest> 
struct pick<Idx, T, TRest...> 
{ 
    typedef typename pick<Idx-1, TRest...>::result result; 
}; 

template <typename Func> 
struct func_traits; 

template <typename TObj, typename R, typename... TArgs> 
struct func_traits<R (TObj::*)(TArgs...)> 
{ 
    typedef R result_type; 

    template <unsigned Idx> 
    struct argument 
    { 
     typedef typename pick<Idx, TArgs...>::result type; 
    }; 
}; 

template <typename Func, 
      typename Traits = func_traits<Func>, 
      typename R = typename Traits::result_type, 
      typename Arg0 = typename Traits::template argument<0>::type, 
      typename Arg1 = typename Traits::template argument<1>::type 
     > 
void foo(Func f) 
{ 
    std::cout << __PRETTY_FUNCTION__ << std::endl; 
}; 

struct thing 
{ 
    void operator()(long, int*) { } 
}; 

int main() 
{ 
    foo(&thing::operator()); 
} 

私は、そのプログラムが出力し:

void foo(Func) [with Func = void (thing::*)(long int, int*), Traits = func_traits<void (thing::*)(long int, int*)>, R = void, Arg0 = long int, Arg1 = int*] 

キーポイントがあることArg0とことはそれぞれlongint*です。

2

ここでは、@BjörnPollex(正しい)答えにC++ 11アップデートを提供します。

質問に戻って、第2引数を明示的に指定する場合は、主に通過できるものを制限するように明示的にdoItを指定します。 C++ 11では、ファンクタの引数型を明示的に知らなくてもこの制限を暗示することができます(ファンクタがとにかくオーバーロードされている場合はあまり定義されていません)。

template < typename FunctorType, class ArgumentType > 
auto doIt(FunctorType functor, ArgumentType arg) -> decltype(bool(functor(arg))) 
{ 
    return functor(arg); 
} 

boolへの変換が、あなたが本当に戻り値の型はboolになりたいように見えるので、私はここにそれを置く必要であっても、できない場合があります)。

このdoIt(テンプレート)関数は、引数functorと互換性があり(またboolに変換可能)引数をとります。渡された引数が互換性がない場合、関数はまったく存在せず、エレガントな "doIt関数が見つかりません"コンパイラエラーが生成されます。

一つはfunctor(arg)からdoItが正確に同等にするために完全な前進を使用して、より一歩を行くことができます:

template < typename F, class A > 
auto doIt(F&& f, A&& a) -> decltype(bool(std::forward<F>(f)(std::forward<A>(a)))) 
{ 
    return std::forward<F>(f)(std::forward<A>(a)); 
} 
関連する問題