参数包扩展问题

时间:2017-02-26 04:51:33

标签: c++ c++11 variadic-templates template-meta-programming

我设法解决了有关初始化静态字符数组的上一个问题,请在此处询问:Initializing a static char based on template parameter

我不喜欢在我的解决方案中需要辅助功能:

//static char arr[N] = {[0]='0', [1]='x', [N-1]='\0',};
// ideally want this, but not currently implemented in g++

template <char... chars>
struct zero_str {};

template <unsigned N, char... chars>
struct seq_gen { using type = typename seq_gen<N-1, '0', chars...>::type; };

template <char... chars>
struct seq_gen<0, chars...> { using type = zero_str<chars...>; };

template <size_t N>
struct zero_gen { using type = typename seq_gen<N-1, '0', '\0'>::type; };

template <>
struct zero_gen<0> { using type = zero_str<'\0'>; };

template<size_t N> using strsize = typename zero_gen<N>::type;

template<typename T, char... chars>
const char* n2hexHelper(T val, zero_str<chars...>)
{
    thread_local static char hexstr[] = {'0', 'x', chars...};
    /* convert to hex */
    return hexstr;
};

template<typename T>
const char* n2hex(T val)
{
    return n2hexHelper<T> (val, strsize<sizeof(T)*2>() );
}

int main()
{
    std::cout << n2hex(1) << std::endl;
    return EXIT_SUCCESS;
}

相反,我宁愿不需要传递给辅助函数的虚拟变量,并且能够做到这样的事情:

template<typename T, char... chars>
const char* n2HexIdeal(T val)
{
    thread_local static char hexstr[] = {'0', 'x', chars...}; //how to get chars... ?
    /* convert to hex */
    return hexstr;
}

我有两个主要问题。 1)参数包扩展可能是我理想的情况吗?或者是强制编译器推导我的char的唯一方法是将它用作函数参数? 2)我对模板元编程不太熟悉,所以我想知道我的上述解决方案是否存在任何明显的错误或惯用错误。

2 个答案:

答案 0 :(得分:1)

如果您可以接受辅助函数是类/结构的静态方法,则可以使用部分特化,如下所示

template <typename, typename>
struct n2hexH;

template <typename T, char ... Chs>
struct n2hexH<T, zero_str<Chs...>>
 {
   static char * func (T const & val)
    {
      thread_local static char hexstr[] = {'0', 'x', Chs...};
      /* convert to hex */
      return hexstr;
    }
 };

现在,您的n2hex()功能变为

template<typename T>
const char* n2hex(T val)
 { return n2hexH<T, strsize<(sizeof(T)<<1U)>>::func(val); }

或者您可以在宏中转换它

#define n2hex(X) n2hexH<decltype(X), strsize<(sizeof(X)<<1U)>>::func(X)

答案 1 :(得分:1)

这在C ++ 14中是可行的。

template<class=void, std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
  return [](auto&& f)->decltype(auto) {
    return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
  };
}
template<std::size_t N>
auto index_over( std::integral_constant< std::size_t, N > ={} ) {
  return index_over( std::make_index_sequence<N>{} );
}

这两个辅助函数允许您扩展一堆std::size_t编译时值,而不需要&#34;自定义&#34;每个使用点的辅助功能。

然后我们可以使用它们:

template<typename T>
const char * toStr(T num)
{
  thread_local static
  auto str = index_over<sizeof(T)*3>()
  ([&](auto...Is)->std::array<char, 3+3*sizeof(T)> {
    return {{ '0', 'x',
      (void(Is),'0')...,
      '\0'
    }};
  });
  // do something with str
  (void)num;
  return str.data();
}

生成并扩展我们的内联参数包。

这需要自动变异lambda,这就是它在C ++ 11中不起作用的原因。

live example