Ссылка на указатель на функцию
Вот так все работает отлично:
#include <iostream>
#include <functional>
void qwer(std::function<void()> &x)
{
x();
}
void e()
{
std::cout << "hello" << std::endl;
}
int main()
{
//void (*ee)() = e;
std::function<void()> ee = e;
qwer(ee);
}
А вот так нет:
#include <iostream>
#include <functional>
void qwer(std::function<void()> &x)
{
x();
}
void e()
{
std::cout << "hello" << std::endl;
}
int main()
{
void (*ee)() = e;
//std::function<void()> ee = e;
qwer(ee);
}
Выдает:
test2.cpp:18:7: error: cannot bind non-const lvalue reference of type ‘std::function<void()>&’ to an rvalue of type ‘std::function<void()>’
18 | qwer(ee);
| ^~
In file included from /usr/include/c++/9/functional:59,
from test2.cpp:2:
/usr/include/c++/9/bits/std_function.h:667:7: note: after user-defined conversion: ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = void (*)(); <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = void; _ArgTypes = {}]’
667 | function<_Res(_ArgTypes...)>::
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test2.cpp:4:34: note: initializing argument 1 of ‘void qwer(std::function<void()>&)’
4 | void qwer(std::function<void()> &x)
| ~~~~~~~~~~~~~~~~~~~~~~~^
Почему он пишет, что ee это rvalue? Ведь это не так.
Ответы (1 шт):
В первом случае типы формального и фактического параметров функции совпадают с точностью до ссылочности. Т.е. функция принимает std::function<void()>&, а передаётся ей экземпляр типа std::function<void()>. В более общем случае T& и T соответственно. Очевидно, что такая привязка допустима, например, такое часто используется для модификации передаваемой в функцию переменной.
Во втором случае переменная имеет тип (указатель на функцию), отличный от std::function<void()>, но который может быть в него преобразован. При этом для обеспечения вызова функции создаётся временная переменная типа std::function<void()>. (Для фундаментальных типов можно привести пример с int и double, где целочисленная переменная может быть неявно преобразована в вещественную.) И в этот раз, чтобы привязка сработала для формального типа должна быть добавлена константность (т.к. язык запрещает привязку временных объектов к неконстантным ссылкам), либо следует убрать ссылочность. В данном случае переменная ee как раз порождает "rvalue" (подробнее о категориях выражений можно почитать здесь), т.е. временную безымянную переменную, для которой ожидается привязка к формальному аргументу x.
Возвращаясь к фундаментальным типам, можно рассмотреть такие варианты:
void f(double d);
void g(double& rd);
void h(const double& crd);
int i = 42;
f(i); // ok. локальная переменная d инициализируется значением i
g(i); // ошибка. int не может быть преобразован в ссылку на double
h(i); // ok. создаётся временный объект типа double и инициализируется значением i