29

operator()状況によっては、callable (関数、関数ポインター、ラムダを使用mem_fnしたオブジェクト インスタンスなど)を型消去できることが望ましい場合があります。タイプが必要です。

std::function理想的ですが、クラス テンプレートをインスタンス化するシグネチャを自動的に決定する方法はないようstd::functionです。任意の callable の関数シグネチャを取得したり、適切な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)>。インスタンスが複数の署名で呼び出し可能な場合 (たとえば、複数の template または default-parameter を持つオブジェクト)、明らかにこれは機能しないと予想されますoperator()

過度に複雑でない非ブースト ソリューションが優先されますが、ブーストは問題ありません。


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

4

3 に答える 3

30

ラムダが持っているという事実を使用して、かなり厄介な非ライブラリソリューションを思いつきました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)); }

これを簡素化または改善できるアイデアはありますか? 明らかなバグはありますか?

于 2012-09-05T13:58:27.837 に答える
2

不可能。一部のoperator()型のアドレスを取得できる場合がありますが、任意の callable のアドレスを取得することはできません。これは、オーバーロードまたはテンプレート パラメーターが含まれている可能性があるためです。それがラムダで機能するかどうかは、明確に定義されていないことは間違いありません。

于 2012-08-09T23:06:50.113 に答える
1

非可変長非ジェネリックのキャプチャレス ラムダ関数と単純なフリー関数の場合、次のアプローチを使用できます。

#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;
}
于 2015-10-21T20:21:31.870 に答える