Будет ли С++ 0x поддерживать __stdcall или extern "C" захват - ничего лямбда?

Вчера я думал о том, можно ли использовать удобство функций С++ 0x лямбда для записи обратных вызовов для функций Windows API.

Например, что, если бы я хотел использовать лямбда как EnumChildProc с EnumChildWindows? Что-то вроде:

EnumChildWindows(hTrayWnd, CALLBACK [](HWND hWnd, LPARAM lParam) {
        // ...
        return static_cast<BOOL>(TRUE); // continue enumerating
    }, reinterpret_cast<LPARAM>(&myData));

Другим вариантом было бы написать обратные вызовы extern "C" для подпрограмм C. Например:.

my_class *pRes = static_cast<my_class*>(bsearch(&key, myClassObjectsArr, myClassObjectsArr_size, sizeof(my_class), extern "C" [](const void *pV1, const void *pV2) {
        const my_class& o1 = *static_cast<const my_class*>(pV1);
        const my_class& o2 = *static_cast<const my_class*>(pV2);

        int res;
        // ...
        return res;
    }));

Возможно ли это?

Я могу понять, что lambdas, которые захватывают переменные, никогда не будут совместимы с C, но мне кажется, что мне кажется, что ящики lambdas не могут быть совместимы.

Ответы

Ответ 1

Lambdas без захвата неявно конвертируется в указатель на функцию (посредством неявной функции преобразования, определенной типом замыкания).

FCD, похоже, не указывает, какой язык связывает тип функции этого типа указателя функции, поэтому, если вам нужно передать этот указатель на функции C, вызывающее соглашение функций С++ и функций C должно быть одинаковым, Я считаю, что в Windows это правда. Таким образом, вы должны иметь возможность передавать функции лямбды в функции Windows API

typedef void(*callbackType)(void *userData);
extern "C" void someCFunction(callbackType callback);

int main() {
  someCFunction([](void *userData) { /* ... */ });
}

Формулировка FCD на 5.1.2/6:

Тип замыкания для лямбда-выражения без лямбда-захвата имеет публичную не виртуальную неявную функцию преобразования const, чтобы указатель на функцию, имеющую тот же параметр и возвращаемые типы, что и оператор вызова функции замыкания. Значение, возвращаемое этой функцией преобразования, должно быть адресом функции, которая при вызове имеет тот же самый эффект, что и вызов оператора вызова функции замыкания.

Я думаю, что в окончательном стандарте должно быть примечание, в котором говорится о том, что есть функция преобразования как указателям на функцию C linkage, так и указателям на функции ссылок С++, поскольку конвертируемость в указатели функций C является одной из целей этой функции.

Ответ 2

Нет особо веских оснований, что это не следует распространять на захват лямбда. Для этого требуется генерация некоторого динамического кода, но он не должен выходить за рамки сценариев компиляторов, и это упростило бы взаимодействие со старыми API-интерфейсами C API - больше не нужно передавать параметры через нетипизированные void * s (что не все API даже предлагают).

Ответ 3

Языковая связь указателя функции, полученная в результате преобразования без лямбда, не указана в стандарте С++ 11, но была адресована в дефект отчет 1557, в котором говорится:

5.1.2 [expr.prim.lambda] в пункте 6 не указывается языковая связь типа функции функции преобразования типа замыкания.

и резолюция заключалась в том, что языковая связь должна быть С++:

Тип замыкания для лямбда-выражения без лямбда-захвата имеет публичную не виртуальную неявную функцию преобразования const, чтобы указатель на функцию с языком С++ (7.5 [dcl.link]). с теми же параметрами и типами возврата, что и оператор вызова функции типа закрытия. Возвращаемое значение...

мы можем найти этот язык в черновом стандарте С++ 14, так как статус DRWP кажется, что это не относится к С++ 11.