2012-08-09 10 views
25

たとえば、呼び出し可能な関数(関数、関数ポインタ、オブジェクトインスタンスoperator()、lambda、mem_fnなど)をタイプイレーズできることが望ましい場合がありますUsing Boost adaptors with C++11 lambdasにあります。ここでは、コピーアサイン可能なデフォルトのコンストラクタブルタイプが必要です。"make_function"のラムダまたは任意の呼び出し可能コードの呼び出しの推測

std::functionは理想的ではなく、自動的にへの道でクラステンプレートstd::functionをインスタンス化するために、どのような署名を決定することがないように思われます。任意の呼び出し可能関数の関数シグネチャを取得し、適切なstd::functionインスタンス化インスタンス(つまり、make_function関数テンプレート)に簡単な方法でラップできますか?

具体的には、私は

template<typename F> using get_signature = ...; 
template<typename F> std::function<get_signature<F>> make_function(F &&f) { ... } 

make_function([](int i) { return 0; })std::function<int(int)>を返すように、どちらか一方を探しています。インスタンスが2つ以上のシグネチャ(例えば、2つ以上のテンプレート、またはデフォルトパラメータoperator()を持つオブジェクトなど)を使用して呼び出し可能な場合、これが動作することは明らかです。

過度に複雑でない非ブースト溶液が好ましいが、ブーストは良好である。


編集:自分の質問に答える。

+1

を。それに対して、私は、イントロスペクション・ファンクタはC++ 11の反パターンのものであると考えています。 'std :: function'が本当に必要であることを確認してください。 –

答えて

27

私はラムダがoperator()を持っていることを利用して、かなり厄介な非ライブラリソリューションを作ってみた:

template<typename T> struct remove_class { }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...)> { using type = R(A...); }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...) const> { using type = R(A...); }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); }; 

template<typename T> 
struct get_signature_impl { using type = typename remove_class< 
    decltype(&std::remove_reference<T>::type::operator())>::type; }; 
template<typename R, typename... A> 
struct get_signature_impl<R(A...)> { using type = R(A...); }; 
template<typename R, typename... A> 
struct get_signature_impl<R(&)(A...)> { using type = R(A...); }; 
template<typename R, typename... A> 
struct get_signature_impl<R(*)(A...)> { using type = R(A...); }; 
template<typename T> using get_signature = typename get_signature_impl<T>::type; 

template<typename F> using make_function_type = std::function<get_signature<F>>; 
template<typename F> make_function_type<F> make_function(F &&f) { 
    return make_function_type<F>(std::forward<F>(f)); } 

これを簡略化または改善することができる任意のアイデア?明らかなバグはありますか?

1は、以下の方法を使用することができます非可変長非ジェネリックcapturelessのラムダ関数と同様に、簡単な無料の機能については
+0

+1。 boolテンプレートパラメータの 'get_signature_impl'とは何ですか? –

+0

@LeonidVolnitskyそれはまったく必要ありません。私はそれを削除しました。私は 'get_signature'を再帰的なテンプレートとして書いていましたが、今は必要ないと思います。 – ecatmur

+0

decltype(&std :: remove_reference :: type :: operator()):: :: typeに&を入れる理由は? – Guillaume07

2

不可能です。 operator()のアドレスを一部のタイプにすることはできますが、任意の呼び出し可能なタイプではありません。オーバーロードやテンプレートパラメータがある可能性があります。ラムダで動作するかどうかは、AFAIKの定義が不明確です。

+0

良い点ですが、私は主にラムダに関係しています。ラムダは正確に1つの 'operator()'が存在します。 – ecatmur

+0

それは確かにそれが事実であるとはっきりと定義されておらず、実際にはそれが存在することが定義されているとは確信していません。 – Puppy

+5

5.1.2:5 *ラムダ式のクロージャータイプには、publicインライン関数呼び出し演算子[...] * – ecatmur

0

:あなたが唯一のYESの場合、ラムダの世話をした場合、あなたはそれが仕事を得ることができます

#include <iostream> 

#include <cstdlib> 

template< typename L, typename R, typename ...A > 
constexpr 
auto // std::function< R (A...) > 
to_function_pointer(L l, R (L::*)(A...) const) 
{ 
    return static_cast< R (*)(A...) >(l); 
} 

template< typename L, typename R, typename ...A > 
constexpr 
auto // std::function< R (A...) > 
to_function_pointer(L l, R (L::*)(A...)) // for mutable lambda 
{ 
    return static_cast< R (*)(A...) >(l); 
} 

template< typename L > 
constexpr 
auto 
to_function_pointer(L l) 
{ 
    return to_function_pointer(l, &L::operator()); 
} 

template< typename R, typename ...A > 
constexpr 
auto // std::function< R (A...) > 
to_function_pointer(R (* fp)(A...)) 
{ 
    return fp; 
} 

namespace 
{ 

void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 

} 

int 
main() 
{ 
    to_function_pointer([]() { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); 
    //to_function_pointer([&]() { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); // can't cast from non-captureless lambda to function pointer 
    to_function_pointer([]() mutable { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); 
    to_function_pointer(f)(); 
    to_function_pointer(&f)(); 
    return EXIT_SUCCESS; 
} 
関連する問題