Spec-Zone.ru › C++

Индексирование пакетов (с C++26)

Доступ к элементу пакета параметров по указанному индексу.

Синтаксис

выражение-идентификатор ...[ выражение ] (1)
имя-типа-typedef ...[ выражение ] (2)
1) Выражение индексирования пакета
2) Спецификатор индексирования пакета
имя-типа-typedef - идентификатор или простой-идентификатор-шаблона, который называет пакет параметров
выражение-идентификатор - выражение-идентификатор, который называет пакет параметров
выражение - преобразованное константное выражение I типа std::size_t, обозначенное как индекс, где I находится в диапазоне [​0​, sizeof...(P)) для некоторого пакета P при индексировании пакета

Объяснение

Индексирование пакета представляет собой расширение пакета нерасширенного пакета параметров, за которым следует многоточие и индекс внутри индексации. Существуют два типа индексирования пакета: выражение индексирования пакета и спецификатор индексирования пакета.

Пусть P — это непустой пакет параметров, содержащий P0, P1, ..., Pn-1, а I — это допустимый индекс, тогда экземпляризация расширения P...[I] даёт элемент пакета PI пакета P.

Индексирование пакета с неконстантным выражением индекса I запрещено.

int runtime_idx();
 
void bar(auto... args)
{
    auto a = args...[0];
    const int n = 1;
    auto b = args...[n];
    int m = 2;
    auto c = args...[m]; // error: 'm' is not a constant expression
    auto d = args...[runtime_idx()]; // error: 'runtime_idx()' is not a constant expression
}

Индексирование пакета шаблонов шаблонов невозможно.

template <template <typename...> typename... Temps>
using A = Temps...[0]<>; // error: 'Temps' is a pack of template template parameters
 
template <template <typename...> typename... Temps>
using B = Temps<>...[0]; // error: 'Temps<>' doesn't denote pack name 
                         // although it is a simple-template-id

Выражение индексирования пакета

выражение-идентификатор ...[ выражение ]

Выражение индексирования пакета обозначает выражение-идентификатор, выражение элемента пакета PI. Выражение-идентификатор должно быть введено объявлением:

  • пакета нетиповых параметров шаблона,
  • пакета параметров функции, или
  • пакета захвата лямбда-выражения.
template <std::size_t I, typename... Ts>
constexpr auto element_at(Ts... args)
{
    // 'args' introduced in function parameter pack declaration
    return args...[I];
}
 
static_assert(element_at<0>(3, 5, 9) == 3);
static_assert(element_at<2>(3, 5, 9) == 9);
static_assert(element_at<3>(3, 5, 9) == 4); // error:  out of bounds
static_assert(element_at<0>() == 1); // error: out of bounds, empty pack
 
// 'Vals' introduced in non-type template parameter pack declaration
template <std::size_t I, std::size_t... Vals>
constexpr std::size_t double_at = Vals...[I] * 2; // OK
 
template <std::size_t I, typename... Args>
constexpr auto foo(Args... args) {
    return [...members = args](Args...[I] op)
    {
        // 'members' introduced in lambda init-capture pack
        return members...[I] + op;
    };
}
 
static_assert(foo<0>(4, "Hello", true)(5) == 9);
static_assert(foo<1>(3, std::string("C++"))("26") == "C++26");

Индексирование пакета сложных выражений, отличных от выражения-идентификатора, запрещено.

template <std::size_t I, auto... Vals>
constexpr auto identity_at = (Vals)...[I]; // error
// use 'Vals...[I]' instead
 
template <std::size_t I, std::size_t... Vals>
constexpr std::size_t triple_at = (Vals * 3)...[I]; // error
// use 'Vals...[I] * 3' instead
 
template <std::size_t I, typename... Args>
constexpr decltype(auto) get(Args&&... args) noexcept
{
    return std::forward<Args>(args)...[I]; // error
    // use 'std::forward<Args...[I]>(args...[I])' instead
}

Применение decltype к выражению индексирования пакета эквивалентно применению decltype к выражению-идентификатору.

void f() 
{
    [](auto... args)
    {
        using T0 = decltype(args...[0]);   // 'T0' is 'double'
        using T1 = decltype((args...[0])); // 'T1' is 'double&'
    }(3.14);
}

Спецификатор индексирования пакета

имя-типа-typedef ...[ выражение ]

Спецификатор индексирования пакета обозначает спецификатор типа-вычисления, тип элемента пакета PI. Имя типа-typedef должно быть введено объявлением пакета параметров шаблонов типов.

template <typename... Ts>
using last_type_t = Ts...[sizeof...(Ts) - 1];
 
static_assert(std::is_same_v<last_type_t<>, int>); // error: out of bounds
static_assert(std::is_same_v<last_type_t<int>, int>);
static_assert(std::is_same_v<last_type_t<bool, char>, char>);
static_assert(std::is_same_v<last_type_t<float, int, bool*>, bool*>);

Спецификатор индексирования пакета может использоваться как:

  • простой спецификатор типа,
  • спецификатор базового класса,
  • спецификатор квалифицированного имени, или
  • тип явного вызова деструктора.

Спецификатор индексирования пакета может использоваться в списке параметров функции или конструктора для задания невыводимых контекстов при выводе аргументов шаблона.

template <typename...>
struct type_seq {};
 
template <typename... Ts>
auto f(Ts...[0] arg, type_seq<Ts...>)
{
    return arg;
}
 
// OK: "Hello" is implicitly converted to 'std::string_view'
std::same_as<std::string_view> auto a = f("Hello", type_seq<std::string_view>{});
 
// Error: "Ok" is not convertible to 'int'
std::same_as<int> auto b = f("Ok", type_seq<int, const char*>{});

Примечания

До C++26, Ts...[N] был допустимым синтаксисом для объявления пакета параметров функции для безымянных массивов размером N. С C++26, Ts...[1] интерпретируется как спецификатор индексирования пакета, что изменило бы поведение ниже на #2. Для сохранения первого поведения пакет параметров функции должен быть именован, например, как функция g.

template <typename... Ts>
void f(Ts... [1]);
 
template <typename... Ts>
void g(Ts... args[1]);
 
void foo() 
{
    f<char, bool>(nullptr, nullptr);
    // behavior #1 (before C++26) 
    //  calls void 'f<char, bool>(char[1], bool[1])'
    // behavior #2 (since C++26): 
    //  error: supposedly called 'void f<char, bool>(bool)'
    //  but provided with 2 arguments instead of 1
 
    g<char, bool>(nullptr, nullptr);
    // calls 'g<char, bool>(char[1], bool[1])'
}
Макрос проверки возможностей Значение Стандарт Функция
__cpp_pack_indexing 202311L (C++26) Индексирование пакетов

Пример

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/pack_indexing

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API