Г
Грокаем C++
@grokaemcpp9.3K подп.
3.6Kпросмотров
38.4%от подписчиков
2 марта 2026 г.
Score: 3.9K
​​Доступ к приватным членам. Явная инстанциация #опытным В прошлый раз мы уже выяснили, что явно инстанцируя шаблонный метод класса, можно написать свою реализацию, которая будет жонглировать непубличными членами в самых виртуозных позах. Но! Мы так и не вышли за пределы класса. Ручная специализация шаблонного метода - это такой же метод класса, поэтому он и умеет трогать приватные поля. Хочется прям снаружи получить доступ к полю и уже не ограничиваться реализацией метода. С++ и это может воплотить в реальность. Хоть стандарт и бьет по рукам за упоминание имен непубличных членов за пределами скоупа класса, все-таки есть исключения из правил: [temp.spec.partial.general]/10 The usual access checking rules do not apply to non-dependent names used to specify template arguments of the&nbsp;simple-template-id&nbsp;of the partial specialization. [temp.spec.general]/6 The usual access checking rules do not apply to names in a declaration of an explicit instantiation or explicit specialization Если по-человечески, то проверка доступа к имени не проверяется при явной специализации и инстанциации шаблона. То есть: class Foo { private: int data = 42; }; template <auto V> struct Bar {}; template struct Bar<&Foo::data>; Этот код вполне влиден. Здесь мы используем указатель на поле класса Foo::data в качестве NTTP. Это валидно, потому что указатель на поле класса - это по сути смещение от начала объекта и оно известно на момент компиляции. Однако, даже если вы явно инстанцируете шаблон, содержащий приватные типы, вы не сможете создать такой объект напрямую. Bar<&Foo::data> b; // error: 'int Foo::data' is private within this context Выход заключается в том, чтобы сохранить значение указателя в статическом члене и передать его в другой класс. template <typename PtrType> struct Storage { inline static PtrType ptr; }; template <auto V> struct PtrTaker { struct Transferer { Transferer() { Storage<decltype(V)>::ptr = V; } }; inline static Transferer tr; }; template struct PtrTaker<&Foo::data>; Когда вы явно инстанцируете&nbsp;PtrTaker<&Foo::data>, его статический член&nbsp;tr&nbsp;будет инициализирован, и в его конструкторе&nbsp;Storage<PtrType>::ptr&nbsp;получит значение. Теперь вы можете получить доступ к нему через: Foo foo; std::cout << foo.Storage<int Foo::>::ptr; Это работает! То есть мы просто взяли и вывели на консоль значение приватного члена класса, при этом никак не меняя его код. Можно также легко его изменить. И все это четко согласовано со стандартом. Еще один раз шаблоны сломали инкапсуляцию. Да что ж это такое! Спасибо, @SoulslikeEnjoyer, за материалы для поста) Exploit loopholes. Stay cool. #cppcore #template #fun
3.6K
просмотров
2748
символов
Нет
эмодзи
Нет
медиа

Другие посты @grokaemcpp

Все посты канала →
​​Доступ к приватным членам. Явная инстанциация #опытным В п — @grokaemcpp | PostSniper