用模板参数填充容器

发布于 2024-09-02 04:52:31 字数 2883 浏览 4 评论 0原文

我想将传递给可变参数模板的模板参数填充到固定长度的数组中。为此,我编写了以下辅助函数模板和

template<typename ForwardIterator, typename T>
void fill(ForwardIterator i) { }

template<typename ForwardIterator, typename T, T head, T... tail>
void fill(ForwardIterator i) {
  *i = head;
  fill<ForwardIterator, T, tail...>(++i);
}

以下类模板

template<typename T, T... args>
struct params_to_array;

template<typename T, T last>
struct params_to_array<T, last> {
  static const std::size_t SIZE = 1;
  typedef std::array<T, SIZE> array_type;

  static const array_type params;

private:
  void init_params() {
    array_type result;
    fill<typename array_type::iterator, T, head, tail...>(result.begin());
    return result;
  }
};

template<typename T, T head, T... tail>
struct params_to_array<T, head, tail...> {
  static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;
  typedef std::array<T, SIZE> array_type;

  static const array_type params;

private:
  void init_params() {
    array_type result;
    fill<typename array_type::iterator, T, last>(result.begin());
    return result;
  }
};

,并通过以下方式初始化了静态常量,

template<typename T, T last>
const typename param_to_array<T, last>::array_type
param_to_array<T, last>::params =
  param_to_array<T, last>::init_params();

现在

template<typename T, T head, T... tail>
const typename param_to_array<T, head, tail...>::array_type
param_to_array<T, head, tail...>::params =
  param_to_array<T, head, tail...>::init_params();

该数组

param_to_array<int, 1, 3, 4>::params

是一个 std::array 并包含值 134。我认为必须有一种更简单的方法来实现这种行为。有什么建议吗?

编辑:正如诺亚·罗伯茨在他的回答中所建议的那样,我修改了我的程序,如下所示:我编写了一个新的结构来计算参数列表中的元素:

template<typename T, T... args>
struct count;

template<typename T, T head, T... tail>
struct count<T, head, tail...> {
  static const std::size_t value = count<T, tail...>::value + 1;
};

template<typename T, T last>
stuct count<T, last> {
  static const std::size_t value = 1;
};

并编写了以下函数

template<typename T, T... args>
std::array<T, count<T, args...>::value>
params_to_array() {
  std::array<T, count<T, args...>::value> result;
  fill<typename std::array<T, count<T, args...>::value>::iterator,
       T, args...>(result.begin());
  return result;
}

现在我得到了

params_to_array<int, 10, 20, 30>()

std::array,内容为 102030。还有进一步的建议吗?

I want to fill the template parameters passed to a variadic template into an array with fixed length. For that purpose I wrote the following helper function templates

template<typename ForwardIterator, typename T>
void fill(ForwardIterator i) { }

template<typename ForwardIterator, typename T, T head, T... tail>
void fill(ForwardIterator i) {
  *i = head;
  fill<ForwardIterator, T, tail...>(++i);
}

the following class template

template<typename T, T... args>
struct params_to_array;

template<typename T, T last>
struct params_to_array<T, last> {
  static const std::size_t SIZE = 1;
  typedef std::array<T, SIZE> array_type;

  static const array_type params;

private:
  void init_params() {
    array_type result;
    fill<typename array_type::iterator, T, head, tail...>(result.begin());
    return result;
  }
};

template<typename T, T head, T... tail>
struct params_to_array<T, head, tail...> {
  static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;
  typedef std::array<T, SIZE> array_type;

  static const array_type params;

private:
  void init_params() {
    array_type result;
    fill<typename array_type::iterator, T, last>(result.begin());
    return result;
  }
};

and initialized the static constants via

template<typename T, T last>
const typename param_to_array<T, last>::array_type
param_to_array<T, last>::params =
  param_to_array<T, last>::init_params();

and

template<typename T, T head, T... tail>
const typename param_to_array<T, head, tail...>::array_type
param_to_array<T, head, tail...>::params =
  param_to_array<T, head, tail...>::init_params();

Now the array

param_to_array<int, 1, 3, 4>::params

is a std::array<int, 3> and contains the values 1, 3 and 4. I think there must be a simpler way to achieve this behavior. Any suggestions?

Edit: As Noah Roberts suggested in his answer I modified my program like the following: I wrote a new struct counting the elements in a parameter list:

template<typename T, T... args>
struct count;

template<typename T, T head, T... tail>
struct count<T, head, tail...> {
  static const std::size_t value = count<T, tail...>::value + 1;
};

template<typename T, T last>
stuct count<T, last> {
  static const std::size_t value = 1;
};

and wrote the following function

template<typename T, T... args>
std::array<T, count<T, args...>::value>
params_to_array() {
  std::array<T, count<T, args...>::value> result;
  fill<typename std::array<T, count<T, args...>::value>::iterator,
       T, args...>(result.begin());
  return result;
}

Now I get with

params_to_array<int, 10, 20, 30>()

a std::array<int, 3> with the content 10, 20 and 30. Any further suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

握住我的手 2024-09-09 04:52:31

无需手动计算参数包中的类型数量,这就是 sizeof... 运算符的用途。此外,我将使 fill() 的迭代器类型可推导,无需显式指定它:

template<typename T, typename FwdIt>
void fill(FwdIt it) { }

template<typename T, T head, T... tail, typename FwdIt>
void fill(FwdIt it) {
    *it = head;
    fill<T, tail...>(++it);
}

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() {
    std::array<T, sizeof...(args)> a;
    fill<T, args...>(a.begin());
    return a;
};

但是参数包也可以在初始化程序列表上下文中扩展,这使得 fill()冗余:

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() {
    std::array<T, sizeof...(args)> a = {{args...}};
    return a;
};

There is no need to count the number of types in a parameter pack manually, thats what the sizeof... operator is for. Additionally i'd make the iterator type for fill() deducible, there is no need to specify it explicitly:

template<typename T, typename FwdIt>
void fill(FwdIt it) { }

template<typename T, T head, T... tail, typename FwdIt>
void fill(FwdIt it) {
    *it = head;
    fill<T, tail...>(++it);
}

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() {
    std::array<T, sizeof...(args)> a;
    fill<T, args...>(a.begin());
    return a;
};

Parameter packs however are also expandable in initializer-list contexts, which makes fill() redundant:

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() {
    std::array<T, sizeof...(args)> a = {{args...}};
    return a;
};
徒留西风 2024-09-09 04:52:31

我可以看到 param_to_array 中终点专业化的唯一原因是这一行:

static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;

由于您的 params_to_array 元函数创建了数组,尽管您最终将实例化大小为 N, N-1, ...., 1 的数组。因此我认为你的对象可以使用组合和单一责任规则的一些帮助。创建另一个可以对参数列表中的元素进行计数的元函数,并使用它来代替此方法。那么你至少可以摆脱 params_to_array 中的递归。

The only reason I can see for a specialization for terminus in param_to_array is this line:

static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;

Since your params_to_array metafunction creates the array though you're going to end up instantiating arrays of size N, N-1, ...., 1. Thus I think your object could use some help from composition and the single responsibility rule. Create another metafunction that can count the elements in a parameter list and use it instead of this method. Then you can get rid of this recursion in params_to_array at the least.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文