Pull to refresh

Comments 6

Даже не знаю что написать в комментарии:) Это реально очень круто, но я потерялся где-то не дойдя до середины, хотя понятно что это очередное нестандартное использование языка. А для рефлексии времени компиляции в большинстве случаев прекрасно подходят старые сишные макросы. А там обычно однотипная задача: описать некоторый список кортежей, который можно использовать для разных целей: объявить из него поля структуры, сделать массив значений, обработать в цикле, загрузить в GUI, сделать сериализацию.

Даже не знаю что написать в комментарии:)

Что пока в стандарте C++ нет чего-то полезного всегда можно попробовать сделать это через Ж дендро-фекальным методом, чтобы благодарные потомки, кому не повезет сопровождать подобный код в будущем, вспоминали автора этих наворотов незлым тихим словом.

Ну вот иногда сишные макросы всё же не подходят. Я писала свой фреймворк с DI и там возникла потребность выявлять зависимости компонентов(Использовался Service Locator с данными нужными в шаблоне).

Если выносить информацию из тела, то это нужно писать бойлерплейт, +меньше диагностируется на КТ, +легко можно ошибиться, а проверка только на рантайме, в сишные макросы это адекватно и не запихнуть.

Пришлось вспоминать про лупхолы и придумывать им такое применение.

Тут затесалась ошибка, делающая даже не UB, а IFNDR.

Во-первых, шаблонная константа kTest инстанцируется в точке первого использования - и далее переиспользуется. Поэтому

static_assert(!kTest<U>);
...
static_assert( kTest<U>);

не прокатит. Либо первый ассерт упадёт, либо второй.

Во-вторых, https://timsong-cpp.github.io/cppwp/temp.constr.constr#temp.constr.atomic-3.sentence-5

Даже если мы будем перезапрашивать выражение у данной шаблонной функции

template<class T, int UniqueID> constexpr bool kTest = requires{.....T....};

static_assert(!kTest<U, __LINE__>);
...
static_assert( kTest<U, __LINE__>);

или чтоб совсем по-хитрому

template<class T, auto F=[]{}> constexpr bool kTest = requires{.....T....};

static_assert(!kTest<U /* , F = some unique lambda */>);
...
static_assert( kTest<U /* , F = some unique lambda */>);

то нарушим указанный пункт стандарта.

Вот можете полюбоваться

https://habr.com/ru/articles/857744/

Поправила, спасибо. Теперь там в requires прокидываются шаблонные аргументы из шаблона главного.

Ещё замечание.

Во-первых, у конструктора (конструкторов) может быть более одной перегрузки. Поэтому Reflect<T> по-хорошему должен был бы отдавать не один кортеж типов, а набор кортежей.

Во-вторых, если конструктор содержит шаблонные аргументы, то Caster сработает криво. Либо конструктор примет его как родного, либо не примет вообще, потому что это будет считаться двойным неявным приведением.

В-третьих, если конструктор принимает initializer_list, - то получится странное

struct X { X(std::initializer_list<int>); };
struct Y { Y(char, std::initializer_list<int>); };

// caster
struct C { template<class T> opertor T() const; };

requires{ X{}; }  // якобы 0-арный
requires{ X{{C{}}}; }  // int - чтобы узнать тип элемента списка

requires{ Y{C{}, C{}}; }  // char, initializer_list<int> - тут всё просто

В-четвёртых, явно объявленные стандартные конструкторы - копирования/перемещения - добавят угару. Даже если они =default.

В общем, техника имеет ряд ограничений, либо её надо допиливать и тестировать на всём безумном сочетании условий.

Sign up to leave a comment.

Articles