Есть ли причина, по которой в c ++ нет std :: iterator для std :: tuple? - PullRequest
3 голосов
/ 21 апреля 2020

Кажется естественным иметь std::iterator для std::tuple. Однако это не реализовано, поэтому программисты реализуют там свои версии. Один из них, например, найден в Блоге Джонатана Мюллера .

Я что-то пропускаю? Есть ли какая-то причина, по которой не существует «официальной версии» для tuple_iterator?

1 Ответ

7 голосов
/ 21 апреля 2020

std::tuple не является контейнером, по крайней мере, в смысле стандартных библиотечных контейнеров. Его нельзя повторить обычными методами, потому что он содержит объекты разных типов. Стандартные контейнеры являются однородными контейнерами, в то время как std::tuple является гетерогенным контейнером.

Это не означает, что вы не можете перебирать кортеж, но это очень громоздко и вы не можете использовать установленный синтаксис:

Давайте представим, что вы хотите перебирать кортеж так же, как вы перебираете контейнер, как std::vector:

std::tuple<int, std::string, bool> t = {...};

for (auto it = t.begin(); it != t.end(); ++it)
{
    auto elem = *it; // this cannot work the same way as with containers
                     // because each element is of a different type
}

Есть пара вещей, которые вы могли бы сделать. Используйте итератор, который содержит std::variant с типами контейнера. Доступ к истинному объекту под ним не так прост. Кроме того, этот тип итератора не может быть использован где-либо еще в стандартной библиотеке, где ожидается итератор, по крайней мере, без дополнительной работы.

Также есть работа над предложением для метапрограммирования (рефлексия, самоанализ). ) который имеет (или имел, не следовал ему) следующий синтаксис:

std::tuple<int, std::string, bool> t = {...};

// something like this (can't remember the syntax exactly):
for constexpr ... (auto elem : t)
{
    // only the common set of operations permitted with `elem`
    // e.g. this is valid
    std::cout << elem << std::endl;

    // this is invalid:
    //elem.size();
}

Это будет фактически развернуто во время компиляции, что приведет к следующему коду:

std::tuple<int, std::string, bool> t = {...};

{
    int elem = std::get<0>(t);
    std::cout << elem << std::endl;
}
{
    std::string elem = std::get<1>(t);
    std::cout << elem << std::endl;
}
{
    bool elem = std::get<2>(t);
    std::cout << elem << std::endl;
}
...