#c #templates #inheritance #constructor #c 17
#c #шаблоны #наследование #конструктор #c 17
Вопрос:
Я изучаю дизайн для проекта, и у меня есть проблема, которую нужно преодолеть. В принципе, мне нужно вызвать конструктор шаблонов visitor_interfaces_t . Ниже приведен упрощенный пример синтаксической работы системы. «Крупномасштабный» проект находится по адресу https://github.com/amatarazzo777/ux_gui_stream и находится в разработке самостоятельно. Объекты организованы так, чтобы их было легко создавать, а также поддерживать. Поэтому мне нравится синтаксис того, как пишется coordinate_t . Однако он работает не так, как я планировал. Каков правильный способ наследовать visitor_interfaces_t и разрешить вызывать конструктор пакета параметров шаблона для него? Диалект C 17. Также приветствуется любое другое тщательное разбиение, например, улучшение дизайна. Заранее спасибо за помощь.
Я нашел другое решение этого вопроса. Я решил разбить процесс трансляции позиции интерфейса и разрешения функции-члена на реализацию.
файл заголовка шаблона (templates_inherit.h)
/**
templates_inherit.h
*/
#ifndef TEMPLATES_INHERIT_H_
#define TEMPLATES_INHERIT_H_
typedef int cairo_t;
typedef double PangoLayout;
class system_base_t {
public:
system_base_t() {
if (!visitor_dispatch_bound)
;
}
virtual ~system_base_t() {}
bool visitor_dispatch_bound = false;
};
template <typename T, typename TC, typename... Args>
class class_storage_emitter_t : public TC,
public Args...,
public system_base_t {
public:
using TC::TC;
class_storage_emitter_t() {}
class_storage_emitter_t(const class_storage_emitter_t amp;other) : TC(other) {}
class_storage_emitter_t(class_storage_emitter_t amp;amp;other) noexcept
: TC(other) {}
class_storage_emitter_t amp;operator=(const class_storage_emitter_t amp;other) {
TC::operator=(other);
return *this;
}
class_storage_emitter_t amp;operator=(class_storage_emitter_t amp;amp;other) noexcept {
TC::operator=(other);
return *this;
}
virtual ~class_storage_emitter_t() {}
};
typedef std::function<void(cairo_t *)> fn_emit_cr_t;
typedef std::function<void(PangoLayout *)> fn_emit_layout_t;
typedef std::variant<std::monostate, fn_emit_cr_t, fn_emit_layout_t>
fn_emit_overload_t;
class visitor_interface_t {
public:
fn_emit_overload_t fn = {};
std::size_t pipeline_order = {};
virtual void bind_dispatch(system_base_t *ptr) {}
};
class visitor_interfaces_base_t {
public:
visitor_interfaces_base_t() {}
virtual ~visitor_interfaces_base_t() {}
std::unordered_map<std::type_index, visitor_interface_t *>
accepted_interfaces = {};
};
template <typename... Args>
class visitor_interfaces_t : public visitor_interfaces_base_t, public Args... {
public:
visitor_interfaces_t() : Args(this)... {}
};
// abstract classes. started having problems when I added
// "interface" function (clue)
template <std::size_t ORDER> class abstract_emit_cr_t : visitor_interface_t {
public:
abstract_emit_cr_t(visitor_interfaces_base_t *ptr) {
pipeline_order = ORDER;
ptr->accepted_interfaces[std::type_index(typeid(fn_emit_cr_t))] = this;
}
void bind_dispatch(system_base_t *ptr) {
fn = fn_emit_cr_t{std::bind(amp;abstract_emit_cr_t::emit,
dynamic_cast<abstract_emit_cr_t *>(ptr),
std::placeholders::_1)};
}
virtual ~abstract_emit_cr_t() {}
virtual void emit(cairo_t *cr) = 0;
};
template <std::size_t ORDER>
class abstract_emit_layout_t : visitor_interface_t {
public:
abstract_emit_layout_t() {}
abstract_emit_layout_t(visitor_interfaces_base_t *ptr) {
pipeline_order = ORDER;
ptr->accepted_interfaces[std::type_index(typeid(fn_emit_layout_t))] = this;
}
void bind_dispatch(system_base_t *ptr) {
fn = fn_emit_layout_t{std::bind(amp;abstract_emit_layout_t::emit,
dynamic_cast<abstract_emit_layout_t *>(ptr),
std::placeholders::_1)};
}
virtual ~abstract_emit_layout_t() {}
virtual void emit(PangoLayout *layout) = 0;
};
const int order_render_option = 3;
class coordinate_storage_t {
public:
coordinate_storage_t() {}
coordinate_storage_t(double _x, double _y, double _w, double _h)
: x(_x), y(_y), w(_w), h(_h) {}
coordinate_storage_t(double _x, double _y) : x(_x), y(_y) {}
virtual ~coordinate_storage_t() {}
double x = {};
double y = {};
double w = {};
double h = {};
};
/**
* classes are named and manufactured like so.
* the parameterized nature of the syntax yields
* a very maintainable source base.
*/
using coordinate_t = class coordinate_t
: public class_storage_emitter_t<
coordinate_t, coordinate_storage_t,
visitor_interfaces_t<abstract_emit_cr_t<order_render_option>,
abstract_emit_layout_t<order_render_option>>> {
public:
using class_storage_emitter_t::class_storage_emitter_t;
coordinate_t() {}
void emit(cairo_t *cr) { std::cout << "emit cr" << std::endl; }
void emit(PangoLayout *layout) { std::cout << "emit layout" << std::endl; }
};
#endif /* TEMPLATES_INHERIT_H_ */
template_inherit.cpp
#include <functional>
#include <type_traits>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <iostream>
#include <any>
#include <variant>
#include "templates_inherit.h"
using namespace std;
int main() {
coordinate_t pos = coordinate_t{10, 10, 500, 500};
pos.init_dispatch();
cout << pos.x << " " << pos.y << " " << pos.w << " " << pos.h << endl;
cairo_t dummy_cr = 1;
PangoLayout dummy_layout = 2;
for (auto n : pos.accepted_interfaces) {
std::visit(
[amp;](auto amp;amp;arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, fn_emit_cr_t>)
arg(amp;dummy_cr);
else if constexpr (std::is_same_v<T, fn_emit_layout_t>)
arg(amp;dummy_layout);
},
n.second->fn);
}
return 0;
}
Комментарии:
1. Это много кода. Для чего он предназначен? В чем ошибка?
2. Вы не передаете никаких аргументов, которые могли бы перейти к
visitor_interfaces_t(Args amp;... args)
. Четыре переданных вами аргумента идут напрямуюcoordinate_storage_t
, и конструктор forclass_storage_emitter_t
никогда не вызывается, потомуclass_storage_emitter_t
что у него нет конструктора, который принимает четыре аргумента. Откуда возьмутся аргументы дляvisitor_interfaces_t(Args amp;... args)
, если вы их не передадите?3. n. местоимения. Извините за объем кода, я хотел быть уверенным, что там будет полная архитектура. Код предназначен для именования объектов, которые могут быть вставлены в поток с использованием оператора <<, который не включен в другую часть базы кода. У меня есть несколько объектов, которые пользователь может создать для предоставления вывода gui с использованием Cairo и Pango. Так, например, есть text_font_t , text_color_t и image_block_t .
4. Джерри, я думал, что аргументы будут поступать из списка наследования в объявлении класса. Но вы правы, конструктор шаблонов никогда не вызывается. Как я мог бы инкапсулировать класс, чтобы определение поддерживало visitor_interfaces_t и вызывало его локально?
5. n. местоимения. эти объекты относятся к разным частям этапа рендеринга. то есть шрифт должен быть загружен и создан до его использования. некоторые объекты имеют разные значения для частей этапа рендеринга, поэтому упоминается порядок рендеринга. Опубликованный интерфейс предоставляет шаблон посетителя.