【问题标题】:Parameter pack expansion questions参数包扩展问题
【发布时间】:2017-02-26 04:51:32
【问题描述】:

我设法解决了之前关于初始化静态 char 数组的问题,在这里问: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)参数包扩展是否可能像我的理想情况一样?或者是强制编译器推断出我的字符的唯一方法......是将它用作函数参数? 2)我对模板元编程不是很熟悉,所以我想知道我的上述解决方案是否存在任何明显的错误或惯用错误。

【问题讨论】:

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


    【解决方案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 编译时值,而无需“自定义”帮助函数。

    然后我们可以使用它们:

    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.

    【讨论】:

    • 我最初是在寻找 C++11 的答案,但我喜欢这个答案让我摸不着头脑。另外,我实现了一个简单的模板结构,它的构造函数只是设置值是一个更惯用的解决方案,但它是一个很好的介绍使用可变参数模板。
    【解决方案2】:

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

    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)
    

    【讨论】:

    • 嗯我仍然不喜欢额外的函数调用,但我想任何体面的优化都会直接转发给函数。是否可能出现以下情况?'template /* 以某种方式使用 U 来获取字符...字符? */>'
    • @MitchLaskis - 可以写成template&lt;typename T, typename U = strsize&lt;sizeof(T)*2&gt;,但是这样你就得不到char ... chars(你没有包chars来扩展)。我知道的唯一方法是将strsize&lt;&gt; 类型的变量(或类型,作为模板参数)传递给另一个函数/方法。
    猜你喜欢
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多