Возврат условного `range_expression`

Какой самый эффективный способ итерации по одному из нескольких известных диапазонов на основе некоторого условия?

псевдокод для двоичного условия:

for element in (condition ? range_a : range_b)
  // do work

Этот "пример" показывает мое намерение использовать цикл for на основе диапазона, но как std::initializer_list имеет ссылочную семантику, это не сработает.

constexpr auto some_range(bool c) -> std::initializer_list<int> {
  if (c) {
    return {1,2};
  } else {
    return {3, 4, 5};
  }
}

bool cond = true; // false

for(auto x : some_range(cond)) {
  // things
}

выходы: warning: returning address of local temporary object [-Wreturn-stack-address]

Во время выполнения я мог вернуть std::vector но это потребовало бы создания нового вектора при каждом вызове:

auto some_range(bool c) -> std::vector<int> {
  if (c) {
    return {1,2};
  } else {
    return {3, 4, 5};
  }
}

Я мог бы использовать фиксированный размер std::array из std::optional<int> но я должен прибегнуть к решению C++14 или C++11.

1 ответ

Решение

Циклический цикл for может перебирать любое выражение e, чей тип класса имеет e.begin() а также e.end() функции-члены или не-функции begin(e) а также end(e) можно найти через ADL. Следовательно, простой итеративный вид может быть:

#include <cstddef>

template <typename T>
struct view
{
    T* p;
    std::size_t s;
    constexpr T* begin() const { return p; }
    constexpr T* end() const { return p + s; }
};

и затем вернул, удерживая указатель на массив с, например, статической продолжительностью хранения:

inline view<const int> conditional_range(bool a)
{
    static int ra[] = { 1, 2 };
    static int rb[] = { 3, 4, 5 };
    if (a) return { ra, 2 };
    else return { rb, 3 };
}

DEMO

Это похоже на то, что C++20 предлагает с std::span,


std::initilizer_list<T> переносит локальный массив, созданный автоматически из заключенного в скобки инициализатора, и поэтому не может использоваться в качестве возвращаемого типа, поскольку в таком случае сохраненные в нем указатели становятся недействительными при выходе из функции.

Другие вопросы по тегам