如何使用构造函数的参数构造成员数组的每个元素

时间:2012-10-11 18:17:12

标签: c++ templates c++11

  

可能重复:
  Convert std::tuple to std::array C++11

假设你有:

template<class T,int N>
struct A {
  A(const B& b): /* what comes here */ {}

  std::array<T,N> F;
};

我需要使用构造函数的参数构造F[]的每个元素,在上面的例子b中。这很棘手,因为参数可能不是可以是编译时常量的类型,如int等。

这与Is it possible to construct the elements of a member array depending on an integral template parameter?不同,因为这里使用了用户定义的结构,因此我们需要它的运行时副本。

2 个答案:

答案 0 :(得分:8)

The indices trick也可以在这里应用,你只需要稍微改变一下:

template <std::size_t... Is>
struct indices {};

template <std::size_t N, std::size_t... Is>
struct build_indices
  : build_indices<N-1, N-1, Is...> {};

template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template<class T,int N>
struct A {
  template<std::size_t... Is>
  A(const B& b, indices<Is...>) : F{{(void(Is),b)...}} {}
  A(const B& b) : A(b, build_indices<N>{}) {}

  std::array<T,N> F;
};

Live example.

我们基本上忽略了索引的值,只使用包本身来执行扩展,即我们只对包的大小感兴趣。重复使用索引似乎是滥用,因为我们对实际值不感兴趣,但我认为重复使用这些机制很好。创建N元素包的任何其他构造看起来都是一样的,除了包很可能只包含零。

答案 1 :(得分:0)

Xeo所示的build_indicies技巧很聪明,如果你的编译器支持它,它可能是最好的选择。

另一种选择可能是允许元素默认构造,然后销毁它们并使用placment new / uninitialized_fill重建它们:

template<class T,int N>
struct A {
  A(const B& b) {
      for (size_t i=0;i<N;++i) {
          F[i].~T();
          new (&F[i]) T(b);
      }
  }

  std::array<T,N> F;
};

您还可以使用无法正常初始化的存储,以避免默认构造:

template<class T,int N>
struct A {    
  typedef std::array<T,N> array_type;
  std::aligned_storage<sizeof(array_type),alignof(array_type)>::type storage;

  array_type &F() {
    return reinterpret_cast<array_type&>(storage);
  }

  A(const B& b) {
    // placement new/uninitialized_fill
  }
};