cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
88 stars 0 forks source link

Возможность создать POD-структуры, для которых тип определяется расположением элементов, concept structs #486

Open topin89 opened 2 years ago

topin89 commented 2 years ago

Идея является альтернативой/дополнением к https://github.com/cpp-ru/ideas/issues/485

Сама идея

Сделать возможным, чтобы часть POD-типов была одинаковой не когда полностью совпадают имена типов и членов типа, а только когда совпадает расположение каждого типа внутри. Пример

concept struct Coords{
    float x; //имена не играют роли
    float y;

    float len() { return std::hypot(x,y); }
};

concept struct xy{
    float X;
    float Y;

    float len_sq() { return x*x + y*y; }
};

std::vector<Coords> a{ {1,2}, {3,4}, {5,6} };
std::vector<xy> b = std::move(a); // Должно компилироваться

Поскольку есть тонны написанного кода, в который новомодные concept struct никто не добавит, может быть, стоит явно сказать компилятору про совпадения типов

struct Coords{
    float x; //имена не играют роли
    float y;

    float len() { return std::hypot(x,y); }
};

struct xy{
    float X;
    float Y;

    float len_sq() { return x*x + y*y; }
};

concept struct coords = {Coords, xy}; // не знаю, как не использовать новые ключевые слова

Применение

Один в один с https://github.com/cpp-ru/ideas/issues/485 Существует достаточно много разных структур координат или rgb-цвета и других подобных, с одинаковым расположением элементов но формально разными типами. И хотя для простых указателей на них ещё можно делать reinterpret_cast и надеяться на лучшее, для вещей вроде vector<vector<Coords>> фокус уже не прокатывает.

Возможные проблемы

Формальное определение одинаковости. Особенно с учётом всех константно-волатильных указателей. Вряд ли смогу сформулировать сам.

Возможно, тоже будут какие-то проблемы со строгим разыменованием, но опять же, не уверен.

Определённо прибавиться работы блокам проверки одинаковости типов, не представляю сколько там её вывалиться. Как вариант, просто объявить любое несовпадение UB и внутри пусть компилятор будет уверен, что одно точно алиас другого до того дня, когда проверки реально введут.

Izaron commented 2 years ago

Как я понимаю, проблема такая - есть два разных типа данных (в смысле что один тип не является алиасом другого), и надо сделать две вещи:

1) Удостовериться, что у них одинаковый layout в памяти 2) Делать "быстро" вещи, которые сейчас делаются "медленно" (например, создание нового вектора и ручное заполнение вместо std::move(x))

Первый пункт в C++XX можно будет выполнить через рефлексию - сравнить количество членов структуры и их типы. Даже не обязательно для POD-типов, можно рекурсивно проверять состав "сложных" типов.

Второй пункт можно выполнить полу-нелегальным образом - как я подозреваю, std::vector<Coords> и std::vector<xy> имеют идентичное представление на стеке и в куче. Поэтому можно будет сделать псевдо-move, скопировав значение стека, как-то так:

std::vector<Coords> v1 = ...; // как-то заполняем...

std::vector<xy> v2;
std::memcpy(&v2, &v1, sizeof(decltype(v1));
// теперь надо как-то сделать амнезию у v1, чтобы он в деструкторе ничего не трогал
// возможно std::memset(&v1, 0, sizeof(decltype(v1));