Использование "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

  1. определение INVOKE (f, t1, t2, ..., tN) следующим образом: ... материал, касающийся указателей функций-членов/var ... - f(t1, t2, ..., tN) во всех остальных случаях.

  2. определение INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN) неявно преобразовано в R.

и поскольку любой тип может быть неявно преобразован в void, ваш код должен быть в порядке с компилятором, соответствующим стандартам. как указано в litb ниже, нет неявного преобразования в void, поэтому это не очень хорошо определено.

[1]: я думаю, что лямбда считается вызываемым объектом здесь, хотя у меня нет ссылки на это. Ваша лямбда также может использоваться в качестве указателя функции не захватывает контекст


похоже, что это может быть нормально для анонимных функций.

цитата из http://www.alorelang.org/release/0.5/doc/std_function.html (это не из стандартной библиотеки C++, однако похоже, что они используют что-то подобное в привязках к C++)

объекты функции могут быть созданы только с определением функции, анонимным выражением функции или путем доступа к связанному методу с помощью точки (.) оператор.

другой способ сделать это - сохранить указатель функции в auto, как показано здесь:http://en.wikipedia.org/wiki/Anonymous_function (раздел C++)