web-dev-qa-db-ja.com

C ++関数パラメーターのタイプを取得する

関数の引数の型を取得し、これらの型をテンプレートパラメーターパックとして渡す標準的な方法はありますか? 以前に行われたことがある であるため、これはC++で可能であることを私は知っています。

私は、C++ 14または今後のC++ 1zで、ここにarg_types<F>...を実装する慣用的な方法があることを望んでいました。

template <typename ...Params>
void some_function(); // Params = const char* and const char*

FILE* fopen(const char* restrict filename, const char* restrict mode);

int main(){
    some_function<arg_types<fopen>...>();
}

明確にするために、これを行うための標準的な方法がないと主張する答えは答えではありません。答えがない場合は、ソリューションがC++ 500に追加されるまで、または宇宙の熱的死まで、どちらか早い方まで、質問に答えないでおくことをお勧めします:)

編集:削除された回答は、PRETTY_FUNCTIONを使用してパラメータータイプの名前を取得できることを示しています。ただし、実際のタイプが必要です。それらのタイプの名前ではありません。

16
Navin

この構文は少し異なります。

まず、タイプはパックよりも扱いやすいため、パックを保持するタイプです。 _using type=types;_は、typesを生成するコードでの作業を節約するだけです。

_template<class...>struct types{using type=types;};
_

これが主力製品です。署名を受け取り、署名の引数を含む_types<?...>_バンドルを生成します。きれいなC++ 14esque構文を取得できるようにするための3つのステップ:

_template<class Sig> struct args;
template<class R, class...Args>
struct args<R(Args...)>:types<Args...>{};
template<class Sig> using args_t=typename args<Sig>::type;
_

構文の違いは次のとおりです。 _Params..._を直接取得する代わりに、_types<Params...>_を取得します。これは、テンプレート関数の型の推定を利用して引数を型リストに移動する「タグディスパッチ」パターンに似ています。

_template <class...Params>
void some_function(types<Params...>) {
}
_

私のfopenは異なります。なぜなら、私は_#include_ ingのものを気にしたくないからです。

_void* fopen(const char* filename, const char* mode);
_

また、構文はfopenに基づいているのではなく、fopentypeに基づいています。ポインタがある場合は、decltype(*func_ptr)などを実行する必要があります。または、使いやすさのためにR(*)(Args...)を処理するようにtopを拡張することもできます。

_int main(){
  some_function(args_t<decltype(fopen)>{});
}
_

実例

これはnotオーバーロードされた関数では機能せず、関数オブジェクトでも機能しないことに注意してください。

一般に、この種のことは悪い考えです。なぜなら、通常、オブジェクトとどのように相互作用しているかを知っているからです。

上記は、関数(または関数ポインター)を取得し、スタックのどこかに引数をポップして、期待されるパラメーターなどに基づいて呼び出す場合にのみ役立ちます。

Boost.FunctionTypes および std::index_sequence 。以下は、関数funcの引数タイプを出力する例です。 doit静的関数を変更して、必要な処理を実行できます。実際の動作をご覧ください ここ

template <typename FuncType>
using Arity = boost::function_types::function_arity<FuncType>;

template <typename FuncType>
using ResultType = typename boost::function_types::result_type<FuncType>::type;

template <typename FuncType, size_t ArgIndex>
using ArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FuncType>, ArgIndex>::type;

void func(int, char, double) {}

template <typename Func, typename IndexSeq>
struct ArgPrintHelper;

template <typename Func, size_t... Inds>
struct ArgPrintHelper<Func, integer_sequence<size_t, Inds...> >
{
  static void doit()
  {
    string typeNames[] = {typeid(ResultType<Arg>).name(), typeid(ArgType<Func, Inds>).name()...};
    for (auto const& name : typeNames)
      cout << name << " ";
    cout << endl;
  }
};

template <typename Func>
void ArgPrinter(Func f)
{
  ArgPrintHelper<Func, make_index_sequence<Arity<Func>::value> >::doit();
}

int main()
{
  ArgPrinter(func);
  return 0;
}

ヘッダー(上記のコードスニペットのノイズを減らすためにここに移動):

#include <boost/function_types/function_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>

#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <Tuple>
#include <utility>
using namespace std;
3
Pradhan