С++ 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
из лямбда-декларации приводит к ошибке, как ожидалось.
Ответы
Ответ 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 &&
.