Использование `std :: function <void (...)>` для вызова не void функции - PullRequest
18 голосов
/ 18 февраля 2012

Некоторое время назад я использовал std::function примерно так:

std::function<void(int)> func = [](int i) -> int { return i; };

По сути, я сделал это, потому что хотел хранить различные функциональные объекты в std::function, но я не хотел ограничивать типы возвращаемых данных функций. Так как это, казалось, сработало, я пошел с этим. Но я не уверен, что это безопасно, и я не смог найти никакой документации по нему. Кто-нибудь знает, является ли это использование законным? Или, в более общем смысле, каковы правила для объекта, который можно безопасно назначить для std::function?

Редактировать

Для пояснения проблема, с которой я сталкиваюсь, заключается в том, что лямбда-функция возвращает int, а func объявляется с типом возврата void. Я не уверен, что это нормально, особенно после того, как сделан вызов func().

Ответы [ 3 ]

20 голосов
/ 18 февраля 2012

Ваш код имеет неопределенное поведение. Это может или не может работать, как вы ожидаете. Причина, по которой он имеет неопределенное поведение, связана с 20.8.11.2.1 [func.wrap.func.con] / p7:

Требуется: F должно быть CopyConstructible. f должно быть Callable (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;
                             ^    ~

По иронии судьбы обоснование такого поведения вытекает из другого вопроса SO .

Другой вопрос представляет проблему с использованием std::function. Решение этой проблемы заключалось в том, чтобы реализация реализовала условие Требуется: во время компиляции. В отличие от этого, решение проблемы этого вопроса - , запрещающее реализации применять Требуется: предложение.

1 голос
/ 18 февраля 2012

Ваш вариант использования четко определен в соответствии со стандартом.

Вы создаете std::function из вызываемого объекта [1]

§20.8.11.2.1 / 7:

template<class F> function(F f);

Требуется: F должен быть CopyConstructible.f должен быть Callable (20.8.11.2) для типов аргументов ArgTypes и возвращаемого типа R.

Так что ваш f вызывается?

§20.8.11.2 / 2 говорит:

Вызываемый объект f типа F называется Callable для типов аргументов 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]: я думаю, что лямбда считается вызываемым объектом, хотя яна это нет ссылки.Ваш лямбда также может быть использован как указатель на функцию, поскольку он не захватывает контекст

0 голосов
/ 18 февраля 2012

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

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

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

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

...