MyFunction

среда, мар. 26, 2025 | 3 минуты чтения

MyFunction

2 семестр
Основы программирования.

Напишем свой класс MyFunction

  1. Он шаблонный и принимает тип указателя на функцию. Как это сделать? Достаточно просто:
template<typename T>
MyFunction
  1. Теперь нам нужен конструктор, который принимает какой-то тип(функтор, функция), либо же 2 разных. Как всё же понять сигнатуру функционального объекта? Делаем специализацию шаблона вокруг другого шаблона:
template<typename R, typename Arg>
class MyFunction<R(Arg)>
  1. Почему не можем написать так сразу? Иначе специализируется то, чего не существует (то есть сразу, когда мы определяем шаблонный класс, у которого в скобках уже есть какой-то тип - это уже специализация)
  2. Нужен оператора скобки:
R operator()(Arg){
	return R{};
}
  1. Нужен конструткор от типов:
private:


public:
MyFunction(TFuncPtr ptr){}

template<typename T>
MyFunction(T func){}

Как положить и лямбду, и функтор в указатель на функцию? — тип на поле класса

Type Eraser

  • Как спрятать TFunc, чтобы в других методах его использовать (нельзя выразить через R и Arg)
    • Делаем чисто виртуальную структуру с чисто виртуальным оператором скобки и пишем её тип в поле
    • Тогда всякий объект будет каститься к нему
    • Чтобы это кастилось, создаём внутри класс, который наследуется от чисто виртуального класса
    • Сделаем этот класс-ребёнок шаблонным и будет хранить поле на наш объект

В чём прикол?

  • Мы в конструктор можем передавать объекты разного типа, которые имеют одну семантику: они принимают аргументы, оператор( ) и бебебе
  • Прячем тип создаваемого объекта
  • Внутри создаём класс, в который кладём этот тип, а этот класс работает семантичеки, также как и все объекты, которые мы хотим передавать
1 идея - можно сделать полною специализацию шаблона, которая тоже является шаблонным классов
2 идея - спрятали объект в шаблон другого объекта(type eraser ?)

.

Касты

  • implicit
  • explicit
    • const
    • static
    • dynamic
    • reintepret
    • C-style cast

Каст чиселок:

  • от меньшего ранга к большему(типа по размеру, шорт можно к инту спокойно)

  • каст если одинаковый ранг, но разный sing?

  • любой указатель можно кастить к войду и от войда, да и все указатели можно друг к другу, потому что один и тот же размер

  • с юинт что-то не то…

  • неявно 0 к фолс

  • в форике инт сравнивается с ансаинд лонг лонг

    • то есть знаковый тип кастится к беззнаковому и происходит переполнение

явный c-style cast

int i = 0;
std::cout << *(double*)&i
int i = 0;
int* p = &1;
double pd = (double*)p;
double d = *pd
  • в инте лежит сначала два последних байта, а потом два первых

  • а вот дабл хранятся иначе, поэтому то же, что и для инта в дабле принимается иначе + разный размер %%примерчик с классами%%

  • в функцию пихаем указатель на другой объект

  • несмотря на то, что в другом объекте нет этого поля, поле и будет интерпретироваться как поле стр…

  • c-style cast - опасная штука, которая никак не проверяет, можем мы ли вообще это делать

const_cast

  • убирает const или volatility с переменной
  • может преобразовывать указатели на одинаковые типы данных
  • может переобразовывать ссылки

[!example] Типичный пример если изначально объект константный, то даже после преобразований указателей, прога не будет арбайтен (UB) забота о работе конст каста лежит на программисте

[!example] Типичный пример в константном методе делать преобразования всё работает только тогда, когда сам объект изначально является неконстантным объектом

[!example] Типичный пример совместимость с c-кодом

static_cast

  • пытается преобразовать с помощью конструткоров и операторов приведения

  • работает в compile-time

  • работает для стандартных типов

  • работает для приведения указателей из одной иерархии

  • может приводить из указателя на void

  • более явный

  • на этапе компилляции будет сказано, если сделать чего-то нельзя

b преобразовывается к int а int кастится к float который передаётся в конструктор для foo

[!example] Типичный пример преобразование классов, находящихся в одной иерархии во втором примерчике поля не присваиваются, j будет лежать после i, поэтому выведется мусор