From 784594faa6db04976539eb8137dda999bdeac4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=9C=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=BD=D0=BA=D0=B5=D0=B2=D0=B8=D1=87?= Date: Tue, 5 Aug 2025 19:38:01 +0700 Subject: [PATCH] =?UTF-8?q?qosd:=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=83=D0=B7=D0=BB=D0=BE=D0=B2=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=BE=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=84=D0=B0=D0=B1=D1=80=D0=B8=D1=87=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Решил обойтись простым ~~советским~~ статическим методом: template class FabricMixin { public: template static std::shared_ptr create(Args&&... args) { return std::shared_ptr(new T(std::forward(args)...)); } }; Ну ладно, он не так просто выглядит на первый взгляд. Но, по сути, всё, что он делает: параметризует метод типом возвращаемого указателя, и передаёт все аргументы как есть в конструктор заданного типа. Решил сделать так, чтобы не копипастить тело конструктора. Ну, вдруг я, например, трассировку туда добавить захочу. Правда, есть недостаток у такого решения: class SimpleNode : ..., public FabricMixin { friend class FabricMixin; Не очень удобное подключение: а) нужно внести по крайней мере две строчки; б) автоматически самого себя параметром шаблона передавать нельзя. Вносить этот метод в `BaseNode` (или около) не хотел, чтобы не пробрасывать оконечный тип по всей иерархии. Да и от указанных выше проблем он не избавляет. Зато можно будет относительно безболезненно выпилить этот класс, если ему подвернётся достойная замена. --- include/mixins/FabricMixin.h | 11 +++++++++++ include/nodes/ComplexNode.h | 6 +++++- include/nodes/SimpleNode.h | 6 +++++- src/main.cpp | 28 +++++++++++----------------- 4 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 include/mixins/FabricMixin.h diff --git a/include/mixins/FabricMixin.h b/include/mixins/FabricMixin.h new file mode 100644 index 0000000..4dc078d --- /dev/null +++ b/include/mixins/FabricMixin.h @@ -0,0 +1,11 @@ +#pragma once +#include + +template +class FabricMixin { +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr(new T(std::forward(args)...)); + } +}; diff --git a/include/nodes/ComplexNode.h b/include/nodes/ComplexNode.h index 8320842..a7c2e8a 100644 --- a/include/nodes/ComplexNode.h +++ b/include/nodes/ComplexNode.h @@ -2,16 +2,20 @@ #include "nodes/BaseNode.h" #include "mixins/HierarchicalLinkMixin.h" +#include "mixins/FabricMixin.h" #include "Logger.h" /// \brief Класс сложного (составного) узла дерева. /// Может содержать несколько дочерних ComplexNode и один SimpleNode. class ComplexNode : public BaseNode, - virtual public HierarchicalLinkMixin { + virtual public HierarchicalLinkMixin, + public FabricMixin { public: ~ComplexNode() { Logger::get("ConDes").dbg(std::string("--- Complex destructor called for: ") + name_); } +private: + friend class FabricMixin; ComplexNode(std::string name) : BaseNode(std::move(name)) { Logger::get("ConDes").dbg(std::string("--- Complex constructor called for: ") + name_); } diff --git a/include/nodes/SimpleNode.h b/include/nodes/SimpleNode.h index 8f6abe1..221d9a0 100644 --- a/include/nodes/SimpleNode.h +++ b/include/nodes/SimpleNode.h @@ -2,17 +2,21 @@ #include "nodes/BaseNode.h" #include "mixins/LazyLinkMixin.h" +#include "mixins/FabricMixin.h" #include "links/OneToOneLink.h" #include "Logger.h" /// \brief Класс простого (листового) узла дерева. /// Может содержать только одного дочернего ComplexNode. class SimpleNode : public BaseNode, - virtual public LazyLinkMixin> { + virtual public LazyLinkMixin>, + public FabricMixin { public: ~SimpleNode() { Logger::get("ConDes").dbg(std::string("--- Simple destructor called for: ") + name_); } +private: + friend class FabricMixin; SimpleNode(std::string name) : BaseNode(std::move(name)) { Logger::get("ConDes").dbg(std::string("--- Simple constructor called for: ") + name_); } diff --git a/src/main.cpp b/src/main.cpp index fee4d06..4e9ec49 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,8 +39,8 @@ int main() { logger.info("Entering main scope..."); { - auto root = std::make_shared("ComplexRoot"); - auto child1 = std::make_shared("ComplexChild1"); + auto root = ComplexNode::create("ComplexRoot"); + auto child1 = ComplexNode::create("ComplexChild1"); root->linkChild(child1); @@ -49,23 +49,21 @@ int main() { std::cout << "\n"; { - auto child2 = std::make_shared("ComplexChild2"); + auto child2 = ComplexNode::create("ComplexChild2"); root->linkChild(child2); - auto subchild2 = std::make_shared("SimpleSubChild2"); + auto subchild2 = SimpleNode::create("SimpleSubChild2"); child2->linkChild(subchild2); - auto child3 = std::make_shared("ComplexChild3"); + auto child3 = ComplexNode::create("ComplexChild3"); root->linkChild(child3); - auto subchild3 = std::make_shared("SimpleSubChild3"); - child3->linkChild(subchild3); + child3->linkChild(SimpleNode::create("SimpleSubChild3")); { // Негативный сценарий 1: попытка добавить второй SimpleNode к ComplexNode try { - auto anotherSimple = std::make_shared("ShouldFail"); - child2->linkChild(anotherSimple); + child2->linkChild(SimpleNode::create("ShouldFail")); logger.err("[ERROR] Не должно было получиться добавить второй SimpleNode к ComplexNode!"); } catch (const std::logic_error& e) { logger.warn(std::string("[Ожидаемое исключение] ") + e.what()); @@ -73,14 +71,12 @@ int main() { // Негативный сценарий 2: попытка добавить ComplexNode к SimpleNode // Это допустимо: SimpleNode может иметь ComplexNode в качестве единственного ребёнка - auto goodComplex = std::make_shared("GoodComplex"); - subchild2->linkChild(goodComplex); + subchild2->linkChild(ComplexNode::create("GoodComplex")); logger.info("[OK] ComplexNode успешно добавлен к SimpleNode как единственный ребёнок."); // Негативный сценарий: попытка добавить второго ребёнка к SimpleNode try { - auto anotherSimple = std::make_shared("ShouldFail2"); - subchild2->linkChild(anotherSimple); + subchild2->linkChild(SimpleNode::create("ShouldFail2")); logger.err("[ERROR] Не должно было получиться добавить второго ребёнка к SimpleNode!"); } catch (const std::logic_error& e) { logger.warn(std::string("[Ожидаемое исключение] ") + e.what()); @@ -88,8 +84,7 @@ int main() { // Негативный сценарий: попытка добавить SimpleNode в ComplexNode, который уже содержит несколько ComplexNode-дочерних try { - auto badSimple = std::make_shared("BadSimple"); - root->linkChild(badSimple); + root->linkChild(SimpleNode::create("BadSimple")); logger.err("[ERROR] Не должно было получиться добавить SimpleNode в ComplexNode с несколькими ComplexNode-дочерними!"); } catch (const std::logic_error& e) { logger.warn(std::string("[Ожидаемое исключение] ") + e.what()); @@ -132,8 +127,7 @@ int main() { } } - auto child4 = std::make_shared("SimpleChild4"); - root->linkChild(child4); + root->linkChild(SimpleNode::create("SimpleChild4")); std::cout << "\nTree flush and link SimpleChild4:\n"; printTreeLadder(*root);