Использование `std :: function ` для вызова не VOID-функции
-
27-10-2019 - |
Вопрос
Некоторое время назад я использовал std::function
В значительной степени нравится это:
std::function<void(int)> func = [](int i) -> int { return i; };
По сути, я сделал это, потому что хотел хранить разные функциональные объекты в std::function
, но я не хотел ограничивать типы возврата этих функций. Поскольку это, казалось, сработало, я пошел с этим. Но я не убежден, что его безопасно использовать, и я не смог найти никакой документации. Кто -нибудь знает, является ли это использование законным? Или, в целом, каковы правила для объекта, который можно безопасно назначить std::function
?
Редактировать
Для разъяснения, проблема, с которой я обеспокоен, заключается в том, что функция Lambda возвращает int
, пока func
объявлен с типом возврата void
. Анкет Я не уверен, что это нормально, особенно после вызова func()
сделан.
Решение
Ваш код имеет неопределенное поведение. Это может работать или не работать так, как вы ожидаете. Причина, по которой он имеет неопределенное поведение, заключается в 20.8.11.2.1 [func.wrap.func.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
Из вызывшего объекта [1
§20.8.11.2.1/7:
template<class F> function(F f);
Требуется: F должен быть подлежащим конструктивным. f Должны быть вызовы (20.8.11.2) для типов аргументов argtypes и return type r.
Так ваш F Callable?
§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
, ваш код должен быть в порядке с компилятором, соответствующим стандартам.
1]: Я думаю, что лямбда считается здесь вызываемым объектом, хотя у меня нет ссылки на это. Ваш лямбда также может быть использован в качестве указателя функции, поскольку он не фиксирует контекст
Похоже, это может быть нормально для анонимных функций.
Цитата от http://www.alorelang.org/release/0.5/doc/std_function.html (Это не из стандартной библиотеки C ++, однако похоже, что они используют что -то подобное в привязках до C ++)
Функциональные объекты могут быть созданы только с определением функции, выражением анонимной функции или путем доступа к связанному методу с использованием оператора Dot (.).
Другой способ, которым это можно было сделать, - это хранение указателя функций в автоматическом виде, как видно здесь: http://en.wikipedia.org/wiki/anonymous_function (Раздел C ++)