【问题标题】:How to get all parameters' types from parameter pack?如何从参数包中获取所有参数的类型?
【发布时间】:2016-12-05 21:30:17
【问题描述】:

我有以下一段代码,其中我使用模板化的static 方法random 定义了struct quick,并具有一些特化:

(我使用了其他 SO 答案中的function_traits。附在底部以供参考。)

struct quick
{
  template <typename T>
  static T random();

  template <typename F>
  static void check(F f)
  {

    constexpr auto arity = function_traits<F>::arity; // easy :)
    std::cout << arity << std::endl;
    typedef typename function_traits<F>::template arg<0>::type type0; // easy:)
    // how to get all types of all F's parameters?
  }
};

template <>
std::string quick::random<std::string>()
{
  return std::string("test");
}

template <>
int quick::random<int>()
{
  return 1;
}

我想在check 中获取F 的所有类型的参数,以便生成带有随机条目的tuple(基于我的random 方法特化)。

像这样:

auto t0 = std::make_tuple(quick::random<AllTypes>()...); //pseudo code
auto t =
    std::make_tuple(quick::random <
                                  function_traits<F>::template arg<std::make_index_sequence<arity>>::type...
                                  >
                                  ()...
                     );

我尝试过类似的东西:

template<typename F, typename ...TIdxs>
using ArgTypes = typename function_traits<F>::template arg<TIdxs>::type...;

// ...
// inside check

typedef ArgTypes<F, std::make_index_sequence<arity>> types;

但惨败:

main.cpp:80:72: error: expected ‘;’ before ‘...’ token
 using ArgTypes = typename function_traits<F>::template arg<TIdxs>::type...;
                                                                        ^
main.cpp: In static member function ‘static void quick::check(F, D)’:
main.cpp:98:15: error: ‘ArgTypes’ does not name a type
       typedef ArgTypes<F, std::make_index_sequence<arity>> types;

我使用了来自this SO answer的function traits 实用程序。

template <typename T>
struct function_traits : function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
    enum { arity = sizeof...(Args) };
    // arity is the number of arguments.

    typedef ReturnType result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
        // the i-th argument is equivalent to the i-th tuple element of a tuple
        // composed of those arguments.
    };
};

【问题讨论】:

  • 像往常一样,函数特性 onky 有时会起作用。 auto f=[](auto&amp;&amp;x){return 2*x;}.

标签: c++ templates c++11 c++14 typetraits


【解决方案1】:

请注意,在function_traits 中,您已经拥有所有参数类型。您所要做的就是公开它们:

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
    enum { arity = sizeof...(Args) };

    using result_type = ReturnType;

    using all_args = std::tuple<Args...>; // <-- add this

    template <size_t i> // <-- consider making this an alias template
    using arg = std::tuple_element_t<i, all_args>;
};

现在,获得所有函数参数的只是function_traits&lt;F&gt;::all_args


如果你不想改变function_traits,我们只需要添加一个外部元函数:

template <class F, class = std::make_index_sequence<function_traits<F>::arity>>
struct all_args;

template <class F, size_t... Is>
struct all_args<F, std::index_sequence<Is...>> {
    using type = std::tuple<typename function_traits<F>::template arg<Is>::type...>;
};

template <class F>
using all_args_t = typename all_args<F>::type;

【讨论】:

    【解决方案2】:
    template<class=void,std::size_t...Is>
    auto tupler(std::index_sequence<Is...>){
      return [](auto&&f){
        return std::make_tuple(
          f(std::integral_constant<std::size_t,Is>{})...
        );
      }
    } 
    template<std::size_t N>
    auto tupler(){
      return tupler(std::make_index_sequence<N>{});
    }
    

    这使您可以内联扩展参数包并生成一个元组。

    简单

    auto t = tupler<ArgCount>()([&](auto i){
      return random<typename func_trait::arg<i>::type>();
    });
    

    func_trait 是上述内容的别名。

    顺便说一句,将struct arg 替换为using 别名。清洁剂。

    【讨论】:

      【解决方案3】:

      不确定这是否是您想要的,但是...用以下方式修改 quick 怎么样?

      struct quick
      {
        template <typename T>
        static T random();
      
        template<typename F, std::size_t I>
           using ArgTypes = typename function_traits<F>::template arg<I>::type;
      
        template<typename F, std::size_t ... Is>
           using ArgTuple = std::tuple< ArgTypes<F, Is>... >;
      
        template <typename F, std::size_t ... Is>
        static ArgTuple<F, Is...> makeArgTuple ()
         { return make_tuple(quick::random<Is>()...); }
      
        template <typename F>
        static void check(F f)
        {
      
          constexpr auto arity = function_traits<F>::arity; // easy :)
          std::cout << arity << std::endl;
      
          typedef typename function_traits<F>::template arg<0>::type type0; // easy:)
      
          auto t = ArgTuple<F, std::make_index_sequence<arity>::type> ();
      
          auto t2 = makeArgTuple<F, std::make_index_sequence<arity>::type>();
        }
      
      };
      

      您将typenames TIdxs 传递给arg 是错误的; arg 需要 std::size_t

      考虑到std::make_index_sequence 这是一个 C++14 特性(但也很容易在 C++11 中创建它)。

      ps:对不起,我的英语不好。

      【讨论】:

      • 关于TIdxs:但我想扩展它以便获得结果:arg&lt;0&gt;, arg&lt;1&gt;, arg&lt;2&gt; ...
      • @Patryk - 当然;但作为std::size_t,而不是typename;我的意思是:没有错template&lt;typename F, typename ...TIdxs&gt;;应该是template&lt;typename F, std::size_t ...TIdxs&gt;
      • 啊,是的。你说得对。但我仍然无法得到我的最终结果auto t = std::make_tuple(quick::random&lt; ...what_here... &gt;());
      • @Patryk - 我明白了...我认为直接不可能,但我修改了答案,添加了makeArgTuple() 方法和使用示例(请参阅auto t2 = ...
      猜你喜欢
      • 1970-01-01
      • 2013-06-14
      • 1970-01-01
      • 1970-01-01
      • 2017-05-17
      • 1970-01-01
      • 1970-01-01
      • 2014-11-27
      • 2012-06-18
      相关资源
      最近更新 更多