23

関数の引数の型を取得し、これらの型をテンプレート パラメーター パックとして渡す標準的な方法はありますか? 以前に行われたので、これが 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、パラメータータイプの名前を取得するために使用できることを指摘しました。ただし、実際の型が必要です。それらのタイプの名前ではありません。

4

4 に答える 4

4

Boost.FunctionTypesとを使用しstd::index_sequenceます。以下は、関数の引数の型を出力する例ですfuncdoit静的関数を変更して、必要なことを行うことができます。実際の動作はこちらでご覧ください。

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;
于 2015-02-13T22:38:38.980 に答える
0

@Yakk に触発されて、少し簡略化したバージョンを次に示します。

  1. まず、ヘルパー メタ関数を定義して、関数の引数の型をタプルとして格納します。

    
    template<typename Sig>
    struct signature;
    template<typename Ret, typename...Args>{
        using type=tuple<Args...>;
    };
    
  2. 概念を使用して入力を機能として制限します

    
    template
    concept is_fun=is_function_v<Fun>;
    
  3. 入力の引数の型を取得する関数「arguments」を次に示します。入力パラメーターに応じて、「引数」関数をオーバーロードして、参照と非参照の両方を受け入れます (フリー関数は常に参照によって渡されます。関数本体を持っている必要さえありません。これはメタ関数であるため、戻り値の型だけで十分です。

    
    template<is_fun T> 
    auto arguments(const T& t)->signature<T>::type;
    
  4. ここにテストがあります:

      
    void foo(const string&, int, double){}
    static_assert(is_same_v<decltype(arguments(foo)),tuple<const string&, int, double>>);
    

ラムダ、ファンクター、メンバー関数ポインターもサポートする本格的なバージョンがここにあります

于 2022-02-02T11:21:06.550 に答える