首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用C++11 initializer_list实现类似std::array的容器

使用C++11 initializer_list实现类似std::array的容器
EN

Stack Overflow用户
提问于 2011-08-13 20:43:21
回答 3查看 4.1K关注 0票数 8

std::array唯一也是非常不方便的一点是,它不能像内置C数组那样从初始化器列表中推断出它的大小,它的大小必须作为模板传递。

有没有可能用C++11 initializer_list实现一个类似std::array的容器(一个围绕内置C数组的薄包装器)?

我之所以这样问,是因为与std::array不同,它会自动从初始化器列表中推断出数组的大小,这要方便得多。例如:

代码语言:javascript
复制
// il_array is the hypothetical container
// automatically deduces its size from the initalizer list 
il_array <int> myarr = {2, 4, 6, 7, 8}; 

如果没有提供初始化器列表,我们还希望提供一个构造函数来指定大小。例如:

代码语言:javascript
复制
// construct a fixed size array of size 10
il_array <int> myarr2 (10); 

这也将使容器与其他标准容器更一致,例如向量、双队列和列表。

据我所知,这是不可能的,因为包装的C数组,例如T元素大小,必须具有恒定的大小和initializer_list的size()成员函数不是恒定的。

此外,我想知道是否有可能使用可变模板实现这样的容器,尽管从我所读到的内容来看,我认为这是不可能的。

EN

回答 3

Stack Overflow用户

发布于 2011-08-14 03:23:58

我认为你在这方面不走运。std::array的最大优点是它是一个POD,并且可以静态初始化。

如果您有一个容器,其构造函数接受一个std::initializer_list,那么它将不得不复制值(除非它只是对初始化器的常量引用,这并不是很有用)。

票数 3
EN

Stack Overflow用户

发布于 2011-12-29 11:47:18

这个怎么样?我使用std::tuple而不是initializer_list,因为在编译时元组参数的数量是可用的。下面的tuple_array类继承自std::array,并添加了一个用于std::tuple的模板化构造函数。元组的内容使用元程序Assign复制到底层数组存储中,它在编译时简单地从N向下迭代到0。最后,make_tuple_array函数接受任意数量的参数并构造一个tuple_array。假设第一个参数的类型是数组的元素类型。优秀的编译器应该使用RVO消除多余的副本。该程序适用于带有RVO的g++ 4.4.4和4.6.1。

代码语言:javascript
复制
#include <array>
#include <tuple>
#include <iostream>

template <size_t I, typename Array, typename Tuple>
struct Assign
{
  static void execute(Array &a, Tuple const & tuple)
  {
    a[I] = std::get<I>(tuple);
    Assign<I-1, Array, Tuple>::execute(a, tuple);
  }
};

template <typename Array, typename Tuple>
struct Assign <0, Array, Tuple>
{
  static void execute(Array &a, Tuple const & tuple)
  {
    a[0] = std::get<0>(tuple);
  }
};

template <class T, size_t N>
class tuple_array : public std::array<T, N>
{
    typedef std::array<T, N> Super;

  public:

    template<typename Tuple>
    tuple_array(Tuple const & tuple)
      : Super()
    {
      Assign<std::tuple_size<Tuple>::value-1, Super, Tuple>::execute(*this, tuple);
    }
};

template <typename... Args>
tuple_array<typename std::tuple_element<0, std::tuple<Args...>>::type, sizeof...(Args)>
make_tuple_array(Args&&... args)
{
  typedef typename std::tuple_element<0, std::tuple<Args...>>::type ArgType;
  typedef tuple_array<ArgType, sizeof...(Args)> TupleArray;
  return TupleArray(std::tuple<Args...>(std::forward<Args>(args)...));
}

int main(void)
{
  auto array = make_tuple_array(10, 20, 30, 40, 50);
  for(size_t i = 0;i < array.size(); ++i)
  {
    std::cout << array[i] << " ";
  }
  std::cout << std::endl;

  return 0;
}
票数 1
EN

Stack Overflow用户

发布于 2011-12-30 04:35:50

我认为这个问题真的很简单。您需要一个类型,该类型的大小将调整为初始化时使用的initializer_list的大小。

代码语言:javascript
复制
// il_array is the hypothetical container
// automatically deduces its size from the initalizer list 
il_array <int> myarr = {2, 4, 6, 7, 8}; 

试试这个:

代码语言:javascript
复制
// il_array is the hypothetical container
// automatically deduces its size from the initalizer list 
std::initalizer_list<int> myarr = {2, 4, 6, 7, 8}; 

这个可以做任何复制吗?在最专业的意义上...是。但是,复制初始值设定项列表并不专门复制其内容。因此,这只需要几个指针拷贝即可。此外,任何值得使用的C++编译器都会省略这个副本。

现在你已经知道了:一个数组的大小是已知的(通过std::initializer_list::size)。这里的限制是:

在compile-time.

  • the阵列上没有大小的阵列是不可用的,mutable.

  • std::initializer_list是非常简单的
  1. 。它甚至没有operator[]。

第三个可能是最烦人的。但它也很容易纠正:

代码语言:javascript
复制
template<typename E> class init_array
{
public:
  typedef std::initializer_list<E>::value_type value_type;
  typedef std::initializer_list<E>::reference reference;
  typedef std::initializer_list<E>::const_reference const_reference;
  typedef std::initializer_list<E>::size_type size_type;

  typedef std::initializer_list<E>::iterator iterator;
  typedef std::initializer_list<E>::const_iterator const_iterator;

  init_array(const std::initializer_list<E> &init_list) : m_il(init_list) {}

  init_array() noexcept {}

  size_t size() const noexcept {return m_il.size();}
  const E* begin() const noexcept {return m_il.begin();}
  const E* end() const noexcept {return m_il.end();}

  const E& operator[](size_type n) {return *(m_il.begin() + n);} 
private:
  std::initializer_list m_il;
};

好了,问题解决了。初始化器列表构造函数确保您可以直接从初始化器列表创建一个初始化器列表。虽然副本不能再被省略,但它仍然只是复制了一对指针。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7050485

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档