Ссылка std::thread и rvalue

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

void Flusher::start(){
    m_continue.store(true);

    m_thread = std::thread([](std::atomic<bool>& shouldContinue){
        while(shouldContinue.load()){
            std::this_thread::sleep_for(std::chrono::seconds(1));
            std::cout << "sec passed" << std::endl;
        }}, std::ref<std::atomic<bool>>(m_continue)
    );
}

Меня беспокоит то, что конструктор std::thread имеет следующую подпись:

template< class Function, class... Args > 
explicit thread( Function&& f, Args&&... args );

Таким образом, в качестве первого и второго аргумента используется ссылка на значение. Если это так, то я не должен использовать shouldContinue после передачи его std::thread конструктор, как это было перенесено.

Конечно, я хочу иметь контроль над этой функцией, и поэтому я хочу использовать shouldContinue в потоке вызывающего, чтобы остановить вызываемую функцию. По понятным причинам я не хочу делать эту переменную глобальной.

Я думаю что std::ref делает там немного магии, но я все еще не уверен, как это работает (я видел std::ref в некоторых примерах при создании новой темы).

Я пытался не заботиться о том, что это ссылка, и я использовал shouldContinue позже ничего не произошло, но я боюсь, что это просто неопределенное поведение. Может кто-нибудь сказать, если приведенный выше код является правильным, а если нет, как это сделать правильно?

1 ответ

Решение

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

Проверьте это для действительно хорошего объяснения:

http://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c/

template <class T>
void func(T&& t) {
}

"Когда && появляется в контексте определения типа, T&& приобретает особое значение. Когда создается экземпляр func, T зависит от того, является ли аргумент, переданный func, lvalue или rvalue. Если это lvalue типа U, T выводится в U&. Если это r-значение, T выводится в U:"

func(4);            // 4 is an rvalue: T deduced to int

double d = 3.14;
func(d);            // d is an lvalue; T deduced to double&

float f() {...}
func(f());          // f() is an rvalue; T deduced to float

int bar(int i) {
  func(i);          // i is an lvalue; T deduced to int&
}

Кроме того, правило свертывания ссылок хорошо читается.

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