Detailed explanation of std::initializer_list

Introduction to std::initializer_list

initializer_list is a new type provided by C++11, which is defined in the header file <initializer_list>. This header file is part of the tool library.

<initializer_list> is defined as follows:

namespace std {
  template<class E> class initializer_list {
  public:
    using value_type = E;
    using reference = const E&;
    using const_reference = const E&;
    using size_type = size_t;
    using iterator = const E*;
    using const_iterator = const E*;
    constexpr initializer_list() noexcept;
    constexpr size_t size() const noexcept; // 元素数量
    constexpr const E* begin() const noexcept; // 首元素
    constexpr const E* end() const noexcept; // 末元素后一位置
  };
  // initializer_list 范围访问
  template<class E> constexpr const E* begin(initializer_list<E> il) noexcept;
  template<class E> constexpr const E* end(initializer_list<E> il) noexcept;
}

 

The std::initializer_list type object is a lightweight proxy object that accesses an array of const T type objects.

std::initializer_list objects are automatically constructed at these times:

  • Initialize an object using a braced initializer list, where the corresponding constructor accepts a std::initializer_list parameter
  • The curly brace initializer list is the right operand of the assignment, or the function call argument, and the corresponding assignment operator/function accepts the std::initializer_list argument.
  • Bind a braced initializer list to auto, included in a scoped for loop

initializer_list can be implemented as a pair of pointers or a pointer and its length. Copying a std::initializer_list does not copy its underlying object.

The underlying array is not guaranteed to survive the lifetime of the original initializer_list object. The storage of std::initializer_list is unspecified (i.e. it can be automatic, temporary or static read-only memory, depending on the occasion). (pre-C++14)

The underlying array is a temporary array of type const T[N] in which each element is copy-initialized from the corresponding element of the original initializer list (unless a narrowing conversion is illegal). The lifetime of the underlying array is the same as that of any other temporary object, except that initializing an initializer_list object from an array extends the lifetime of the array just as binding a reference to the temporary does (with exceptions, such as for initializing non-static class members). The underlying array can be allocated in read-only memory. (since C++14)

If an explicit or partial specialization of std::initializer_list is declared, the program is ill-formed.

1. Member type

member type definition
value_type T
reference const T&
const_reference const T&
size_type std_size_t
iterator const T*
const_iterator const T*

2. Member functions

Constructor

initializer_list() noexcept; (since C++11) (before C++14)
constexpr initializer_list() noexcept; (since C++14)

 

#include <iostream>
#include <initializer_list>
int main(){
    std::initializer_list<int> empty_list;
    std::cout << "empty_list.size(): " << empty_list.size() << '\n';
    // 用列表初始化创建初始化器列表
    std::initializer_list<int> digits {1, 2, 3, 4, 5};
    std::cout << "digits.size(): " << digits.size() << '\n';
    // auto 的特殊规则表示‘ fraction '拥有类型
    // type std::initializer_list<double>
    auto fractions = {3.14159, 2.71828};
    std::cout << "fractions.size(): " << fractions.size() << '\n';
}

 

The result is as follows:

  • size  : Returns the number of elements in initializer_list
  • begin : Returns a pointer to the first element
  • end : Returns a pointer to the position after the last element

3.Non-member functions

std::begin(std::initializer_list) (C++11) Specialized std::begin
std::end(std::initializer_list)(C++11) defined in header file specialized std::end
rbegin(std::initializer_list) (C++14) specialized std::rbegin
rend(std::initializer_list)(C++14) specialized std::rend

 

#include <iostream>
#include <vector>
#include <initializer_list>
template <class T>
struct S {
    std::vector<T> v;
    S(std::initializer_list<T> l) : v(l) {
         std::cout << "constructed with a " << l.size() << "-element list\n";
    }
    void append(std::initializer_list<T> l) {
        v.insert(v.end(), l.begin(), l.end());
    }
    std::pair<const T*, std::size_t> c_arr() const {
        return {&v[0], v.size()};  // 在 return 语句中复制列表初始化
                                   // 这不使用 std::initializer_list
    }
};
template <typename T>
void templated_fn(T) {}
int main(){
    S<int> s = {1, 2, 3, 4, 5}; // 复制初始化
    s.append({6, 7, 8});      // 函数调用中的列表初始化
    std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";
    for (auto n : s.v)
        std::cout << n << ' ';
    std::cout << '\n';
    std::cout << "Range-for over brace-init-list: \n";
    for (int x : {-1, -2, -3}) // auto 的规则令此带范围 for 工作
        std::cout << x << ' ';
    std::cout << '\n';
    auto al = {10, 11, 12};   // auto 的特殊规则
    std::cout << "The list bound to auto has size() = " << al.size() << '\n';
//    templated_fn({1, 2, 3}); // 编译错误!“ {1, 2, 3} ”不是表达式,
                             // 它无类型,故 T 无法推导
    templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
    templated_fn<std::vector<int>>({1, 2, 3});           // 也 OK
}

The result is as follows:

Guess you like

Origin blog.csdn.net/hulinhulin/article/details/133444819