Функция шаблона вызывает ошибку компилятора при использовании с локальной лямбда - PullRequest
5 голосов
/ 28 июля 2011

Мой предыдущий вопрос пришел к выводу, что для использования POSIX makecontext с лямбда-функцией C ++ (т. Е. Функциональным объектом) может потребоваться неприятное «двойное приведение». Теперь я столкнулся с ошибкой компиляции, связанной со следующим минимальным кодом:

#include <iostream>
#include <ucontext.h>

using namespace std;

template <typename T> void foo()   {
  ucontext_t c;
  auto f = [=](int i){ cout << i << endl; };
  makecontext(&c, (void (*) (void)) (void (*)(int)) f, 1, 12345);
}

int main(int argc, char *argv[]) {
  foo<int>();
  return 0;
}

Ошибка:

error: invalid cast from type ‘foo() [with T = int]::<lambda(int)>’ to type ‘void (*)(int)’

Однако, если я удаляю неиспользуемый (в этом примере) аргумент шаблона из функции foo, он становится void foo();, и меняем вызов на foo(), ошибка исчезает. Может кто-нибудь сказать мне, почему? Я использую G ++ 4.6.

Edit:

Из приведенных ниже комментариев кажется, что [=] в приведенном выше коде делает лямбду «захватывающей» лямбда, несмотря на тот факт, что она на самом деле ничего не захватывает. [=] не требуется в моем коде, увы, замена на [] в GCC 4.6 не устраняет ошибку. Я сейчас устанавливаю GCC 4.6.1 ...

Ответы [ 2 ]

5 голосов
/ 28 июля 2011

Если вы используете [=], чтобы вызвать лямбду, вы не получите указатель на функцию (или объект, который можно преобразовать в единицу). Вы получите функцию object . И никакое количество заклинаний не позволит вам передать это на makecontext. Ни в коем случае это не работает.

Согласно N3291, самый последний рабочий проект C ++ 0x:

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

Это только место, где спецификация допускает преобразование в указатель на функцию. Следовательно, если последние версии GCC разрешают преобразование в указатели функций для [=], это не соответствует спецификации.

3 голосов
/ 28 июля 2011

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

Измените [=] на [] в объявлении f, и оно должно работать как положено.

РЕДАКТИРОВАТЬ: Тот факт, что это компилируется с более поздними версиями GCC (как отметил Kerrek), дает четкое указание на то, что это просто ошибка компилятора в используемой вами версии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...