Сделать лямбду не копируемой / неподвижной - PullRequest
3 голосов
/ 20 февраля 2020

Рассмотрим следующий код :

#include <iostream>
#include <thread>

int main() {
    std::thread t;
    const auto l = [x = std::move(t)]{};
    decltype(l) m = std::move(l);
}

Этот код не компилируется со следующими сообщениями:

prog.cc: In function 'int main()':
prog.cc:7:32: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)'
    7 |     decltype(l) m = std::move(l);
      |                                ^
prog.cc:6:37: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed:
    6 |     const auto l = [x = std::move(t)]{};
      |                                     ^
prog.cc:6:37: error: use of deleted function 'std::thread::thread(const std::thread&)'
In file included from prog.cc:2:
/opt/wandbox/gcc-head/include/c++/10.0.1/thread:154:5: note: declared here
  154 |     thread(const thread&) = delete;
      |     ^~~~~~

Is Есть ли способ сделать лямбда не копируемой или неподвижной без явного захвата какой-либо непереписываемой переменной (т.е. оставляя [] пустым)?

1 Ответ

7 голосов
/ 20 февраля 2020

Вы можете написать простой огибающий агрегат, который будет препятствовать перемещению и копированию.

struct NoCopyMove {
    NoCopyMove(NoCopyMove const&) = delete;
    NoCopyMove(NoCopyMove&&)      = delete;

    void operator=(NoCopyMove const&) = delete;
    void operator=(NoCopyMove&&)      = delete;
};

template<class Functor>
struct Fixed : Functor, NoCopyMove {
    using Functor::operator();
};

template<typename F>
Fixed (F&&) -> Fixed<std::decay_t<F>>;

Для использования в таком виде

const auto l = Fixed{[]{}};

NoCopyMove - это простой миксин, который отключает копирование и перемещение. Написание этого способа позволяет нам сохранить специализации Fixed в виде простых агрегатов.

Все, что делает Fixed, - это наследование / инициализация в качестве базового (с гарантированным исключением копирования, когда это возможно) для функтора, который он задается как аргумент. А затем выставьте его operator().

Поскольку в нем нет участвующих членов (кроме, может быть, в Functor), и поскольку лямбда не может наследовать от нашего пользовательского класса NoCopyMove, пустые базовые оптимизации запускаются для безгражданства лямбды. Таким образом, объекты не должны быть больше, чем лямбда, с которой вы их инициализируете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...