Использование "std:: function" для вызова функции Non-void
некоторое время назад я использовал std::function
примерно так:
std::function<void(int)> func = [](int i) -> int { return i; };
в основном, я сделал это, потому что я хотел хранить различные объекты функции в std::function
, но я не хотел ограничивать возвращаемые типы этих функций. Так как это, казалось, сработало, я пошел с ним. Но я не уверен, что он безопасен в использовании, и я не смог найти никакой документации по нему. Кто-нибудь знает, является ли это использование законным? Или, в более общем плане, каковы правила для объекта который можно безопасно назначить std::function
?
редактировать
для уточнения, проблема, с которой я обеспокоен, заключается в том, что лямбда-функция возвращает int
, а func
объявляется с типом возврата void
. Я не уверен, что это нормально, особенно после вызова func()
сделано.
3 ответов
ваш код имеет неопределенное поведение. Это может сработать, а может и нет, как вы ожидаете. Почему это неопределенное поведение из-за 20.8.11.2.1 [Функ.упаковка.функция.con] / p7:
требуется:
F
должно бытьCopyConstructible
.f
должен вызываться (20.8.11.2) для типов аргументовArgTypes
и возвращаемого типаR
.
на f
для вызова типа возврата R
, f
должен вернуть что-то неявно конвертируемое в возвращаемый тип std::function
(void
в вашем случае). И int
неявно конвертируется в void
.
я ожидал бы, что ваш код будет работать на большинстве реализаций. Однако по крайней мере на одной реализации (libc++), он не компилируется:
test.cpp:7:30: error: no viable conversion from 'int (int)' to 'std::function<void (int)>'
std::function<void(int)> ff = f;
^ ~
по иронии судьбы причина проистекает из еще один вопрос.
другой вопрос представлял проблему с std::function
использование. Решение что проблема необходимости осуществления исполнения требуется: положение во время компиляции. Напротив, решение проблемы этого вопроса -запрещает реализация от применения требуется: предложения.
ваш случай использования хорошо определен в соответствии со стандартом.
вы строите std::function
из callable объект[1]
§20.8.11.2.1/7:
template<class F> function(F f);
требует: F должен быть CopyConstructible. f должен быть вызываемым (20.8.11.2) для типов аргументов ArgTypes и возвращение Р. типа
так ваш f вызываемый?
§20.8.11.2/2 говорит:
вызываемый объект f тип F вызывается для argtypes типов аргументов и верните тип R, если выражение
INVOKE (f, declval<ArgTypes>()..., R)
, рассматриваемый как недооцененный операнд (Пункт 5), хорошо сформирован (20.8.2).
и определение INVOKE
говорит:
§20.8.2
определение
INVOKE (f, t1, t2, ..., tN)
следующим образом: ... материал, касающийся указателей функций-членов/var ... -f(t1, t2, ..., tN)
во всех остальных случаях.определение
INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN)
неявно преобразовано вR
.
и поскольку любой тип может быть неявно преобразован в как указано в litb ниже, нет неявного преобразования в void, поэтому это не очень хорошо определено.void
, ваш код должен быть в порядке с компилятором, соответствующим стандартам.
[1]: я думаю, что лямбда считается вызываемым объектом здесь, хотя у меня нет ссылки на это. Ваша лямбда также может использоваться в качестве указателя функции не захватывает контекст
похоже, что это может быть нормально для анонимных функций.
цитата из http://www.alorelang.org/release/0.5/doc/std_function.html (это не из стандартной библиотеки C++, однако похоже, что они используют что-то подобное в привязках к C++)
объекты функции могут быть созданы только с определением функции, анонимным выражением функции или путем доступа к связанному методу с помощью точки (.) оператор.
другой способ сделать это - сохранить указатель функции в auto, как показано здесь:http://en.wikipedia.org/wiki/Anonymous_function (раздел C++)