Передача ссылки на итератор с помощью std :: thread завершится неудачно, если контейнер не является ссылкой в ​​вызывающей функции - PullRequest
1 голос
/ 05 июня 2019

вот моя проблема:

У меня есть класс с членом-контейнером, скажем std::vector. У меня есть функция, скажем, parallelStuff, которая принимает ссылки на итераторы этого контейнера и выполняет с ним все. Я хочу выполнить указанную функцию параллельно, используя std::thread

Я реализовал это, и он отлично работает. Теперь я хотел написать очень похожую установку с одним небольшим отличием: в рабочей версии, в функции, которая вызывает потоки на parallelStuff, я получаю итераторы из ссылки на контейнер.

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

Это минимальный рабочий пример для репликации проблемы:

#include <thread>
#include <vector>

class Foo {
public:
    Foo() {}
    auto const & member() { return member_; }
    void parallelStuff(std::vector<int>::const_iterator & it,
                       std::vector<int>::const_iterator const & end) {
        // do stuff while it != end
    }
private:
    std::vector<int> member_;
};


int main(int argc, char * argv[]) {
    auto foo = Foo();
    auto& member = foo.member();
    // auto member = foo.member();  <-- copy instead of reference, this fails!
    auto it = member.begin();
    auto end = member.end();
    auto t = std::thread(&Foo::parallelStuff, &foo,
                         std::ref(it), std::ref(end));
    t.join();

    return 0;
}

Как уже говорилось, если я использую копию member вместо ссылки, я получаю ошибку

/usr/include/c++/8/thread:120:17: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues

Поиск в сообщении об ошибке привел меня только к сайту , объясняющему, что мне нужно обернуть эталонные параметры в std::ref(), что я уже делаю.

Кто-нибудь понимает, что здесь не так, и, пожалуйста, объясните это (и как это исправить)?

Большое спасибо!

PS: я использую gcc version 8.3.0 (Ubuntu 8.3.0-6ubuntu1~18.04) с -std=c++17

1 Ответ

1 голос
/ 05 июня 2019

Функция parallelStuff ожидает получения константных итераторов , и вы должны предоставить их.

Вы можете получить константных итераторов :

  1. путем вызова cbegin / cend на объекте

или

по вызову begin / end на постоянном объекте

В строке ниже

auto member = foo.member();

автоматическое удержание типа работ, которые отбрасывают ссылочность и константность из инициализатора.Так что member просто объявлено как vector<int>.Так что begin / end возвращает vector<int>::iterator, что не соответствует аргументам parallelStuff.

Чтобы получить const итераторов для неконстантного объекта, просто вызовите cbegin/ cend:

auto it = member.cbegin();
auto end = member.cend();

LIVE DEMO


Это работает

auto& member

, поскольку member выводится какconst vector<int>&, поэтому begin / end, вызываемый для объекта const, возвращает итераторы const - vector<int>::const_iterator, что соответствует объявлению parallelStuff.

...