Странная ошибка компиляции при использовании вложенной лямбды - PullRequest
2 голосов
/ 19 января 2012

Я написал некоторый код с использованием лямбды на vc2010. Упрощенная структура кода выглядит следующим образом:

template<typename Functor>
bool f1(int a, Functor& f)
{
    return f(a+1);
}

template<typename Functor>
bool f2(Functor& f)
{
    return f(1);
}

template<typename Functor>
bool f3(Functor& f)
{
    return f2([&](int a) -> bool {
        // (1) Works
        auto test = [&](int b) -> bool { return f(a+b); };
        return f1(a, test);

        // (2) Doesn't work         
        //return f1(a, [&](int b) -> bool { return f(a+b); });
    });
};

int main()
{
    int a = 100;

    f3([&](int b) { return (a+b)%2 == 0; });
}

Сначала я написал вложенный лямбда-код как (2), а vc10 выдает непонятное сообщение об ошибке, как показано ниже

'f1' : cannot convert parameter number from 'int' to 'int &'

Однако код (1) работает хорошо, который идентичен (2), за исключением lvalue-ness.

Мой вопрос:

  1. Соответствует ли код (2) стандарту C ++ 11?
  2. Если нет, то в чем причина этого странного поведения компиляции?

Ответы [ 3 ]

4 голосов
/ 19 января 2012

GCC 4.6 выдает следующую ошибку:

a.cpp: в функции 'int main()':
a.cpp: 30: 43: ошибка: отсутствует функция сопоставления для вызова 'f3(main()::<lambda(int)>)'
a.cpp: 30: 43: примечание: кандидат:
a.cpp: 14: 6: примечание: bool f3(Functor&)Functor = main()::<lambda(int)>]
a.cpp: 14: 6: примечание: нет известного преобразования для аргумента 1 из 'main()::<lambda(int)>' в 'main()::<lambda(int)>&'

Что более понятно: ваши лямбды являются временными, и вы пытаетесь связать их со ссылками на l-значение. Так что просто используйте ссылки на r-значения или вообще никаких ссылок:

template<typename Functor>
bool f1(int a, Functor&& f)
{
    return f(a+1);
}

template<typename Functor>
bool f2(Functor&& f)
{
    return f(1);
}

template<typename Functor>
bool f3(Functor&& f)
{
    return f2([&](int a) -> bool {
        // (1) Works
        auto test = [&](int b) -> bool { return f(a+b); };
        return f1(a, test);

        // (2) Doesn't work         
        //return f1(a, [&](int b) -> bool { return f(a+b); });
    });
};

int main()
{
    int a = 100;

    f3([&](int b) { return (a+b)%2 == 0; });
}

Не знаю, сможет ли VS это скомпилировать, но GCC делает это правильно.

4 голосов
/ 19 января 2012
return f1(a, [&](int b) -> bool { return f(a+b); });

Здесь второй аргумент, который является лямбда-выражением, является временным объектом, который нельзя привязать к неконстантной ссылке. Я считаю, что сообщение об ошибке вводит в заблуждение; это точно не говорит о проблеме. Хороший компилятор выведет лучшее сообщение об ошибке. Попробуйте GCC или Clang.

Исправление таково: второй аргумент не ссылается:

template<typename Functor>
bool f1(int a, Functor f)  //I removed `&` from the second parameter
{
    return f(a+1);
}

Аналогично, сделайте все параметры Functor в других функциях не ссылочными. Передавать функтор как ссылку не имеет особого смысла, особенно в C ++ 11, в котором вы также можете передавать лямбду, которую вы можете определить на лету.

0 голосов
/ 19 января 2012

Как уже говорили другие, вы не можете привязать временную ссылку к неконстантной ссылке.

Есть 3 способа исправить это:

  1. передать по значению:

    шаблон bool f1 (int a, Functor f) { вернуть f (a + 1); }

  2. передать по значению:

    шаблон bool f1 (int a, Functor && f) { вернуть f (a + 1); }

  3. передать по значению:

    шаблон bool f1 (int a, const Functor & f) { вернуть f (a + 1); }

Я бы выбрал 3-й вариант (проход по lvalue или константе).

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