如何从参数包中获取所有参数的类型?

时间:2016-07-31 20:14:58

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

我有以下代码,我用struct quick方法static定义了random,其中包含一些特殊化:

(我使用了来自其他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;
}

我想在F中获取所有类型的check参数,以便我可以生成带有随机条目的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;

我使用了来自thisfunction 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.
    };
};

3 个答案:

答案 0 :(得分:5)

请注意,在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<F>::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;

答案 1 :(得分: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别名。清洁器。

答案 2 :(得分:-1)

不确定这是你想要的,但是......如何以下列方式修改module.exports = { formatAMPM: (date, inclSecs=false) => { let hours = date.getHours(); let minutes = date.getMinutes(); let seconds = date.getSeconds(); let ampm = hours >= 12 ? 'PM' : 'AM'; let strTime= '' hours = hours % 12; hours = hours ? hours : 12; // the hour '0' should be '12' minutes = minutes < 10 ? '0'+ minutes : minutes; seconds = seconds < 10 ? '0'+ seconds : seconds; if (inclSecs) { strTime = hours + ':' + minutes + ':' + seconds + ' ' + ampm; } else { strTime = hours + ':' + minutes + ' ' + ampm; } return strTime; } }

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>(); } }; typename传递给TIdxs; arg需要arg

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

p.s:抱歉我的英语不好。