
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.75] |
![]() |
|
Страницы: (17) « Первая ... 15 16 [17] все ( Перейти к последнему сообщению ) |
![]() |
Сообщ.
#241
,
|
|
У C++ нет таких возможностей для того, что не может быть разрешено в компайл-тайм и требует линк-тайм. Например, полноценные мультиметоды. Но можно к такому приблизиться очень близко. Если ты имеешь в виду что-то типа рефлексии, то это уже не грамматика. Но её тоже обещают через пару лет, посмотрим
|
![]() |
Сообщ.
#242
,
|
|
Оказалось, что препроцессор я в руки брал ещё давнее, чем мне казалось. Мне было лень возиться со списками типов, но я вспомнил за вариадик-макросы, и думал, что они мне помогут. Не помогли. Вылетело из головы, что макросы в принципе нерекурсивны, и вариадики этого не изменяют. Так что нужно было бы по старинке, нумеровать 1, 2, 3 итд до нужного количества, которые бы ссылались на предыдущие.
В общем пофик. Нате нормальную версию. Препроцессор остался только в определении параметров, потому что удобно. Но и там можно от него избавиться, если обеспечить уникальность типов свойств как-нибудь иначе. ![]() ![]() #include <cstdint> #include <source_location> #include <iostream> #include <functional> #include <type_traits> #include <cstring> template <typename Param> struct Node { using value_type = Param; static value_type set(value_type& l, const value_type& r) { return l = r; } static value_type get(const value_type& v) { return v; } static inline const value_type default_value = value_type{}; }; template <typename T, std::uint_least32_t L, std::uint_least32_t C> struct Value_Base { static const std::uint_least32_t line = L; static const std::uint_least32_t column = C; using node_type = Node<T>; using value_type= typename node_type::value_type; value_type value; Value_Base(): value(node_type::default_value) {} Value_Base& operator=(const typename node_type::value_type& v) { value = v; return *this; } }; template <typename Type> struct Value: public Type { public: using node_type = typename Type::node_type; using value_type= typename node_type::value_type; value_type Name; public: explicit Value(const value_type& v = node_type::default_value): Name(v) {} }; #define Prop(Type) \ typedef struct Value_Base<Type, std::source_location::current().line(), \ std::source_location::current().column()> struct NullType{}; template <typename T, typename H> struct TList; template <typename T, typename L, typename R> struct TList<T, TList<L, R>> { using Node = T; using Tail = TList<L, R>; }; template <typename T> struct TList<T, NullType> { using Node = T; using Tail = NullType; }; template <typename N, typename ...Args> struct MakeList { using type = TList<Value<N>, typename MakeList<Args...>::type>; }; template <typename N> struct MakeList<N> { using type = TList<Value<N>, NullType>; }; template <typename N, typename ...T> using MakeTList = typename MakeList<N, T...>::type; template <typename N, typename ...T> using MakeProps = typename MakeTList<N, T...>::type; template <typename F, typename Param> struct Builder: public Param::Node, public Builder<F, typename Param::Tail> { template <typename Args> void setArgs(Args &&args) { auto &value = static_cast<Value<std::remove_reference_t<Args>>&>(*this); using node_type = typename std::remove_reference_t<decltype(value)>::node_type; node_type::set(value.Name, args.value); } auto getValue() { auto &value = static_cast<typename Param::Node&>(*this); using node_type = typename std::remove_reference_t<decltype(value)>::node_type; return node_type::get(value.Name); } explicit Builder(F f): Builder<F, typename Param::Tail>(f) {} template <typename ...Args> typename std::function<F>::result_type call(Args... args) { return Builder<F, typename Param::Tail>::call(args..., getValue()); } template <typename ...Args> typename std::function<F>::result_type operator()(Args... args) { (setArgs(args), ...); return call(); } }; template <typename F> struct Builder<F, NullType> { std::function<F> fn; explicit Builder(F f): fn(f) {} template <typename ...Args> typename std::function<F>::result_type call(Args... args) { return (this->fn)(args...); } }; void f(int x, int y, int z) { std::cout << x << '\t' << y << '\t' << z << std::endl; } Prop(const char*) param1; Prop(const char*) param2; Builder<decltype(strcmp), MakeTList<param1, param2>> build(strcmp); Prop(int) par1; Prop(int) par2; Prop(int) par3; Builder<decltype(f), MakeTList<par1, par2, par3>> f_proxy(f); int main() { std::cout << build(param1() = "abc", param2() = "abc") << std::endl; std::cout << build(param1() = "abc", param2() = "abd") << std::endl; std::cout << build(param2() = "abd", param1() = "abc") << std::endl; std::cout << build(param1() = "abd") << std::endl; std::cout << build(param2() = "ab" ) << std::endl; f_proxy(par2() = 456, par1() = 789); f_proxy(par3() = 123); } Добавлено Majestio, разобрался с вашим доблестным компилером онлайн. Во-первых, ему нужно явное включение <cstdint>, чтобы были доступны определения типов типа uint_least32_t. Что очень странно, ибо этот тип используется в классе std::source_location, и он должен его включать сам. Ну ок, как бы не обязан, и как-то выкручивается. Во-вторых, ему категорически не травится атрибут noexcept у strcmp(), из-за которого он отказывается конкретизировать параметр std::function<> и идёт по обобщённой ветке, которая не реализована, и это правильно. Правильно, что не реализована для не подходящего типа, но вот то, что noexcept-функция является неподходящей – это ни разу не правильно. И это хороший вопрос к тамошней реализации STL, разбирайся с этой байдой сам, тут я не помощник. Во всяком случае ты можешь заменить std::function<> просто на указатель и везде вместо длинных bla_bla::return_type наставить auto. Должно работать, но это уж точно костыль. |
Сообщ.
#243
,
|
|
|
![]() |
Сообщ.
#244
,
|
|
А что тогда не костыль с твоей точки зрения, D_KEY? Не, лучше не так. Дай определение термина "костыль", плз. Списки типов изобрёл Александреску, и ничего лучше пока не придумали. Да, есть вариадики, но это не эквивалент, т.к. их невозможно надёжно специализировать, постоянно выползают неоднозначности сопоставления, т.к. ... стремится попадать под что угодно. Автоматическую генерацию иерархий классов по спискам тоже он изобрёл, и что-то получше пока только обещают. Рекурсивный обход иерархии, применяя указанную стратегию к каждому узлу, опять же его заслуга. По факту весь шаблонный метапрогамминг от него, мои первые мультиметоды на C++03 зарелизились. Если подзабыл, то это изобретения более чем 20-летней давности, так что если б были намерения заменить на более другое, давно б уже зарелизили в Стандарте.
Добавлено Цитата D_KEY @ Он не умеет C++20. Внезапно std::source_location ему неведом. В плане онлайн компиляторов, я лучше godbolt пока не видел. |
Сообщ.
#245
,
|
|
|
Цитата Qraizer @ Цитата D_KEY @ Он не умеет C++20. Внезапно std::source_location ему неведом.В плане онлайн компиляторов, я лучше godbolt пока не видел. А ты какой компилятор выбрал? А ключик прописал? Добавлено Цитата Qraizer @ Дай определение термина "костыль" Хороший вопрос. На общее определение не претендую, но я бы сформулировал как "обходной путь для решения проблемы, который использует какие-то нестандартные и зачастую ненадежные инструменты, когда полноценное решение недоступно или слишком дорого". Как правило имеет ограничения и может привести к другим проблемам при использовании для решения исходной. |
Сообщ.
#246
,
|
|
|
Вот твой код с msvc и c /std:c++20
Добавлено Цитата Qraizer @ ему категорически не травится атрибут noexcept у strcmp(), из-за которого он отказывается конкретизировать параметр std::function<> и идёт по обобщённой ветке, которая не реализована, и это правильно. Правильно, что не реализована для не подходящего типа, но вот то, что noexcept-функция является неподходящей – это ни разу не правильно. И это хороший вопрос к тамошней реализации STL С этим интересно было бы разобраться, кстати. И gcc и clang не компилят. А они стандарту обычно следуют лучше msvc. На днях может быть посмотрю. Или если ты глянешь, то напиши. |
Сообщ.
#247
,
|
|
|
Вообще, все верно, clang и gcc правы. std::function не умеет работать с noexcept функциями (а с C++17 они другой тип). Но твой код будет работать, если взять std::move_only_function из С++23
![]() |
![]() |
Сообщ.
#248
,
|
|
Цитата D_KEY @ Ну т.е. ты сейчас обозвал костылями любые библиотеки. Ок.На общее определение не претендую, но я бы сформулировал как "обходной путь для решения проблемы, который использует какие-то нестандартные и зачастую ненадежные инструменты, когда полноценное решение недоступно или слишком дорого И к слову, что ты имеешь против надёжности тут? Во-первых, это не библиотека, а только лишь концепт. Во-вторых, я бы не назвал свои мультиметоды ненадёжными. И они целиком и полностью отвечают Стандарту. Почитай их фичи. Как бы взятые оттуда решения не будут менее надёжными и в этом концепте. У меня складывается впечатление, что ты просто не понимаешь, для чего вообще применяется метакод. Не открою большой секрет, если скажу, что как раз для того, чтобы научить компилятор делать то, что ранее он был делать не способен. Качество такого обучения естественно зависит от обучающего, так что костыли могут попадаться. Но не априори же. |
Сообщ.
#249
,
|
|
|
Цитата Qraizer @ И они целиком и полностью отвечают Стандарту. Не вдаваясь в подробности, и нагло влезая в ваш спич ... спешу сообщить - твой аргумент говно ![]() ![]() |
![]() |
Сообщ.
#250
,
|
|
Что б далеко не ходить, D_KEY, вот что на гитхабе написано:
Цитата Чего тут реально не хватает, так это возможности раскидать перекрытия базового мультиметода по разным единицам трансляции, т.к. для этого требуется либо перенести компиляцию частично в линк-тайм, либо перенести разрешение перегрузки в ран-тайм. Остальное использование практически никак не ограничивает обычное использование обычных функций, расширяя однако его до возможности позднего связывания некоторых (или всех) аргументов.Добавлено Если UB задокументировано в Стандарте, то её наличие в языке не проблема. Многие реализации доопределяют те или иные аспекты, Стандарт оставляет за ними такое право как раз для непереносимых аспектов исполнительных платформ. Например, разыменование nullptr во многих реализация более чем допустимо, т.к. там лежат таблицы векторов прерываний, например. Программа при этом не будет соответствовать Стандарту, т.к. корректно отработать ей на другой реализации запросто будет невозможным, однако конкретно в этой реализации она будет иметь строго определённое поведение. За эти качества C/C++ и получили свою нишу, которую у них отобрать непросто. Надёжность кода измеряется ...немного другими метриками. |
Сообщ.
#251
,
|
|
|
Цитата Qraizer @ Если UB задокументировано в Стандарте, то её наличие в языке не проблема. Многие реализации доопределяют те или иные аспекты, Стандарт оставляет за ними такое право как раз для непереносимых аспектов исполнительных платформ. Например, разыменование nullptr во многих реализация более чем допустимо, т.к. там лежат таблицы векторов прерываний, например. Программа при этом не будет соответствовать Стандарту, т.к. корректно отработать ей на другой реализации запросто будет невозм Не сочти за неуважение ![]() ![]() |
Сообщ.
#252
,
|
|
|
Qraizer, ты с godbolt разобрался, увидел ссылку мою? Там можно выбрать разные компиляторы (и архитектуры) и ключи разные прописать. Очень удобно.
Добавлено И про noexcept согласен с комментарием? Добавлено Цитата Qraizer @ Цитата D_KEY @ Ну т.е. ты сейчас обозвал костылями любые библиотекиНа общее определение не претендую, но я бы сформулировал как "обходной путь для решения проблемы, который использует какие-то нестандартные и зачастую ненадежные инструменты, когда полноценное решение недоступно или слишком дорого Нет, не любые. Иногда это как раз прямой путь со стандартными подходами и надежными инструментами ![]() В данном случае не костылями была бы такая реализация, которая действительно работала бы на уровне синтаксического сахара. Это могла бы быть и библиотека, если бы у C++ были для этого средства. Или если бы данный кейс можно было бы разрулить за счет исключительно метапрограммирования и, например, компайл-тайм рефлексии. |