Подтвердить что ты не робот

С++ 11 lambda может быть назначено на std:: function с неправильной подписью

Следующие компиляции и запуска (в версии Apple LLVM версии 6.1.0 и Visual С++ 2015):

#include <functional>
#include <iostream>

struct s { int x; };

int main(int argc, char **argv)
{
    std::function<void (s &&)> f = [](const s &p) { std::cout << p.x; };
    f(s {1});
    return 0;
}

Почему присваивание std::function<void (s &&)> f = [](const s &p) { std::cout << p.x; }; не генерирует ошибку? Функция, принимающая ссылку rvalue, не должна иметь такую ​​же подпись, как функция, принимающая ссылку const lvalue, если она? Удаление const из лямбда-декларации приводит к ошибке, как ожидалось.

4b9b3361

Ответ 1

Чтобы расширить существующий комментарий и ответ:

Точка std::function<R(A...)> заключается в том, что она может обернуть любую функцию или функтор, который можно вызвать с помощью A..., и получить результат в R.

Итак, например,

std::function<int(int)> f = [](long l) { return l; };

просто персиковый.

Итак, что вы должны спросить себя, когда увидите что-то вроде этого: если у вас есть лямбда, принимающая const T &, и у вас есть выражение типа T && (или, точнее, у вас есть значение x типа T), можете ли вы использовать это выражение для вызова лямбда?

Да, вы можете.

И если вы можете, то std::function должен иметь возможность хранить этот функтор. Это в значительной степени главная точка std::function.

Ответ 2

Пожалуйста, возьмите это с солью. Это то, что я понимаю, но я не уверен.

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

int main(int argc, char **argv)
{
  std::cout <<  std::is_convertible<s &&, s&>::value << std::endl;       //false                                                      
  std::cout <<  std::is_convertible<s &&, const s&>::value << std::endl; //true                                                     

  std::cout <<  std::is_convertible<const s &, s&&>::value << std::endl; //false                                                     
  return 0;
}

Это показывает, что можно преобразовать a s && в const s&. Вот почему назначение std::function в порядке.

Отбрасывание константы из лямбда-декларации создает как ожидалось.

Действительно, это потому, что (как показано выше) преобразование a s && в s & невозможно.

Точно так же, попробуйте противоположное:

std::function<void (const s &)> f = [](s &&p) { std::cout << p.x; }; завершится с ошибкой, потому что невозможно преобразовать a const s&  до s &&.