С++ 11 lambdas могут получить доступ к моим частным членам. Зачем?

Рассмотрим этот фрагмент кода:

class shy {
private:
    int dont_touch;    // Private member

public:
    static const shy object;
};


const shy shy::object = []{
    shy obj;
    obj.dont_touch = 42;   // Accessing a private member; compiles; WHY?
    return obj;
}();


int main()
{
}

Живой код (Clang)

Живой код (GCC)

Кажется, это действительно неинтуитивно для меня. Что говорит об этом стандарт С++ 11/14? Является ли это ошибкой GCC/Clang?

Ответ 1

Как уже было сказано в комментариях @Tony D и @dyp:

§ 9.4.2/2 Элементы статических данных [class.static.data]:

Выражение инициализатора в определение члена данных static входит в сферу его класса.

Вышеупомянутое означает, что члены static данных и их инициализаторы могут обращаться к другим членам private и protected своего класса.

Также восстанавливается стандарт § 5.1.2/2 & 3 Лямбда-выражения [expr.prim.lambda]:

2 Оценка lambda-выражения приводит к временному присвоению (12.2). Это временное называется закрывающим объектом. Лямбда-выражение не должно появляться в неоцененном операнде (п. 5). [Примечание: объект замыкания ведет себя как объект функции (20.9).-End note]

3 Тип лямбда-выражения (который также является типом объекта замыкания) - это уникальный, неназванный тип типа ununion, называемый типом замыкания, свойства которого описаны ниже. Этот тип класса не является совокупностью (8.5.1). Тип замыкания объявляется в наименьшей области блока, области видимости класса или области пространства имен, которая содержит соответствующее лямбда-выражение.

Сопоставляя вышеизложенное, мы заканчиваем вывод о том, что объект временного закрывания prvalue вашей лямбда объявлен и определен в инициализаторе элемента данных static const shy::object и, следовательно, область действия объекта лямбда-закрытия - это область class shy.. Таким образом, он может обращаться к частным членам class shy.