11

私はsignature_ofという名前のメタ関数を書き込もうとしています。このメタ関数は、関数(ポインター)、ファンクター、またはラムダのタイプを指定すると、そのシグネチャを返します。

これが私がこれまでに持っているものです:

#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>

#include <type_traits>

template <typename F>
struct signature_of_member
{
    typedef typename boost::function_types::result_type<F>::type result_type;
    typedef typename boost::function_types::parameter_types<F>::type parameter_types;
    typedef typename boost::mpl::pop_front<parameter_types>::type base;
    typedef typename boost::mpl::push_front<base, result_type>::type L;
    typedef typename boost::function_types::function_type<L>::type type;
};

template <typename F, bool is_class>
struct signature_of_impl
{
    typedef typename boost::function_types::function_type<F>::type type;
};

template <typename F>
struct signature_of_impl<F, true>
{
    typedef typename signature_of_member<decltype(&F::operator())>::type type;
};

template <typename F>
struct signature_of
{
    typedef typename signature_of_impl<F, std::is_class<F>::value>::type type;
};

実際の作業のほとんどはboost::function_typesライブラリによって行われるため、これは非常に簡単です。一般的な考え方は次のとおりです。

  • std :: is_classを使用して、組み込み関数(ラムダを含む)とファンクターを区別します
  • 組み込み関数型の場合、boost :: function_types::function_typeを使用してそのシグネチャを取得します
  • ファンクターの場合は、operator()のタイプを取得し、そのシグネチャを取得し、それをドクターして「this」パラメーターを削除します。

これは組み込み関数で機能します。

int f(int);
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

ラムダの場合:

auto f = [](int) { return 0; }
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

関手用:

struct A
{
    int operator()(int);
};
typedef signature_of<A>::type Sig;  // Sig is int(int)

ただし、bind()式(ファンクターの特殊なケース)では機能しません。私がこれを試してみると:

#include <functional>
int g(int);
typedef signature_of<decltype(std::bind(g, 0))>::type Sig;

コンパイラエラーが発生します:

In file included from test.cpp:3:0:
signature_of.hpp: In instantiation of 'signature_of_impl<
        _Bind<int (*(int))(int)>, true
    >':
signature_of.hpp:45:74:   instantiated from 'signature_of<
        _Bind<int (*(int))(int)>
    >'
test.cpp:21:52:   instantiated from here
signature_of.hpp:39:74: error: type of '& _Bind<
        int (*)(int)({int} ...)
    >::operator()' is unknown

問題は、bind()によって返されるファンクターのoperator()がテンプレートであるため、そのタイプを判別できないことです。

bind()式の署名を別の方法で取得することは可能ですか?

4

2 に答える 2

11

バインダーの operator() がテンプレート化されているという事実よりも多くの問題があり、パラメーターの数も任意です。任意の数の追加引数を使用して bind の結果を呼び出すことができるはずであることを思い出してください。例えば:

int f(int);

auto bound = boost::bind(f, _2);

boundは 2 つ以上の任意の数の引数で呼び出されるようになりましたが、実際には 2 番目の引数のみが関数に転送されます。

基本的に、別の答えが言ったように、このオブジェクトには署名がありません。その署名は、使用方法によってのみ定義されます。

于 2011-01-23T00:24:33.883 に答える
4

オペレーターがテンプレート化されている場合、署名はありません。

于 2011-01-22T23:58:17.173 に答える