Подтвердить что ты не робот

С++ 11 требует, чтобы этот лямбда был объявлен изменчивым?

Рассмотрим этот код С++ 11:

#include <functional>
#include <cstdlib>

template <typename F>
void test(F &&f) {
    auto foo = [f]() {
        f();
    };
    foo();
}

int main() {
    test(std::bind(std::puts, "hello"));
    return 0;
}

GCC и Clang принимают это как действительный код С++ 11, но Visual Studio 2013 требует, чтобы лямбда была объявлена ​​изменчивой (auto foo = [f]() mutable { ... }). В противном случае я получаю эту ошибку:

ошибка C3848: выражение, имеющее тип 'const std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>', потеряло бы некоторые константно-летные квалификаторы, чтобы вызвать 'int std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>::operator ()<>(void)'

Является ли Visual Studio правом отклонять этот код без изменчивости, или это действительно С++ 11?

(Любопытно, что Clang отклоняет код, если вы меняете std::bind(std::puts, "hello") на std::bind(std::exit, 0), по-видимому, потому, что он считает, что noreturn делает тип функции другим, я совершенно уверен, что это ошибка.)

4b9b3361

Ответ 1

Это не о лямбдах.

#include <functional>
#include <cstdlib>

int main() {
  const auto x = std::bind(std::puts, "hello");
  x();
}

Это принято GCC, но отклонено MSVC.

В стандарте неясно, действительно ли это, ИМО. Возвращаемое значение g of std::bind имеет неопределенный тип возврата, для которого g(...) действителен и определен в терминах cv-квалификаторов g, но стандарт фактически не говорит, что любой operator() должен быть вызванным для const -qualified объектов или ссылок. Это сильно означает, что это должно быть действительно, потому что в противном случае ссылка на g cv-квалификаторы кажется бесполезной, но на самом деле она не говорит, что она действительна.

Из-за этого я считаю, что поведение MSVC не соответствует стандартным авторам, но, тем не менее, может соответствовать требованиям стандарта.

Ответ 2

Это выглядит как ошибка в реализации Visual Studio bind, возвращая тип только с оператором вызова неконстантной функции. Он должен возвращать тип, который пересылает все вызовы функций объекту связанной функции, независимо от собственной квалификации cv.

Чтобы обобщить довольно непрозрачный язык С++ 11 20.8.9.1.2, вызовы функций на результат bind должны быть перенаправлены на объект связанной функции и поэтому должны быть разрешены, если вызовы на этом объекте будут позволил. Таким образом, это была бы ошибка, если объект связанной функции не был бы разрешен, если const; но здесь, будучи указателем функции, он может быть вызван независимо от cv-квалификаций.