【问题标题】:How to initialise an array of N function pointers to function templates indexed from 0..N-1?如何初始化从 0..N-1 索引的函数模板的 N 个函数指针数组?
【发布时间】:2016-10-23 14:01:01
【问题描述】:

给定一个函数指针数组function_sig,我想将它初始化为一组模板函数指针,这些指针通过模板参数作为索引。这可能吗?

例如

template<int I>
void fn() { /* do something */ }

typedef void(*function_sig)();

template<int ARRAY_SIZE>
struct items
{
  static function_sig array[ARRAY_SIZE];
};

template<int ARRAY_SIZE>
function_sig items<ARRAY_SIZE>::array = { /* what do I put here? */ };

那么,我可以在初始化列表中添加一些东西,以便将 items&lt;ARRAY_SIZE&gt;::array 初始化为 { fn&lt;0&gt;, fn&lt;1&gt;, ..., fn&lt;ARRAY_SIZE-1&gt; }

注意:我知道一种使用预处理器魔法的方法,但我想尝试不使用它。目前,我想我将不得不取消数组并将其替换为像数组一样的东西,但这会导致在索引伪数组时搜索 O(N),我'不想做。

【问题讨论】:

标签: c++ arrays c++11 initializer-list static-initialization


【解决方案1】:

问题是得到一个从 0 到 ARRAY_SIZE - 1 的可变范围。

我提出了一个解决方案,将array转移到基类itemsH

#include <iostream>


template <std::size_t ...>
struct range
 { };

template <std::size_t N, std::size_t ... Next>
struct rangeH 
 { using type = typename rangeH<N-1U, N-1U, Next ... >::type; };

template <std::size_t ... Next >
struct rangeH<0U, Next ... >
 { using type = range<Next ... >; };


template<int I>
void fn() { std::cout << "[" << I << "]" << std::endl; }

typedef void(*function_sig)();

template <typename T>
struct itemsH;

template <std::size_t ... RNG>
struct itemsH<range<RNG...>>
 {
   static function_sig array[sizeof...(RNG)];
 };

template<std::size_t ARRAY_SIZE>
struct items : public itemsH<typename rangeH<ARRAY_SIZE>::type>
 { };

template <std::size_t ... RNG>
function_sig itemsH<range<RNG...>>::array[sizeof...(RNG)] = { fn<RNG>... };


int main ()
 {
   items<10>  i_10;

   for ( unsigned ui = 0U ; ui < 10 ; ++ui )
      i_10.array[ui]();

   return 0;
 }

p.s.:我已将ARRAY_SIZE 的类型从int 更改为size_t;希望不是问题

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

--- 编辑:添加 C++14 示例 ---

如果你(当你)可以使用 C++14,你可以使用std::index_sequencestd::make_index_sequence,扔掉rangerangeH

例子变成

#include <utility>
#include <iostream>


template<int I>
void fn() { std::cout << "[" << I << "]" << std::endl; }

typedef void(*function_sig)();

template <typename T>
struct itemsH;

template <std::size_t ... RNG>
struct itemsH<std::index_sequence<RNG...>>
 { static function_sig array[sizeof...(RNG)]; };

template<std::size_t ARRAY_SIZE>
struct items : public itemsH<std::make_index_sequence<ARRAY_SIZE>>
 { };

template <std::size_t ... RNG>
function_sig itemsH<std::index_sequence<RNG...>>::array[sizeof...(RNG)]
   = { fn<RNG>... };


int main ()
 {
   items<10>  i_10;

   for ( unsigned ui = 0U ; ui < 10 ; ++ui )
      i_10.array[ui]();

   return 0;
 }

【讨论】:

  • 您的英语很好,切换到std::size_t 也很好。我只使用了int,因为我很懒。 :D 我通常会使用std::size_t
【解决方案2】:
#include <array>

template<int... Is>
struct int_seq { };

namespace detail {

template<int I, int... Is>
struct make_int_seq : make_int_seq<I - 1, I, Is...> { };

template<int... Is>
struct make_int_seq<0, Is...> {
    using type = int_seq<0, Is...>;
};

} // namespace detail

template<int SizeN>
using make_int_seq = typename detail::make_int_seq<SizeN - 1>::type;

template<int I>
void fn() { /* do something */ }

//typedef void(*function_sig)();
using function_sig = void(*)();

template<int ARRAY_SIZE>
struct items {
    static std::array<function_sig, ARRAY_SIZE> array;
};

template<int... Is>
std::array<function_sig, sizeof...(Is)> create_items_array(int_seq<Is...>) {
    return {{ &fn<Is>... }};
}

template<int ARRAY_SIZE>
std::array<function_sig, ARRAY_SIZE> items<ARRAY_SIZE>::array
  = create_items_array(make_int_seq<ARRAY_SIZE>{});

Online Demo

在 C++14 中,int_seq 等人消失了,取而代之的是std::integer_sequence 等人。

【讨论】:

  • @Adrian : 不,C 数组不可复制,因此无法从函数中返回,我们需要 create_items_array 工厂函数。
  • 仅供参考,升级到 c++14 时必须进行一些细微的修改,因为您的 make_int_seq 将生成 0..N,而 std::make_integer_sequence 将生成 0..N-1 .
  • @Adrian : No, it doesn't,我不知道你为什么认为它会......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
相关资源
最近更新 更多