Зарегистрируйте типы для std::variant программноC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Зарегистрируйте типы для std::variant программно

Сообщение Anonymous »

Введение
Я собираюсь изменить формулировку своего вопроса, поскольку люди, похоже, не понимают, какова цель.
Поскольку я получаю массу комментариев, предлагающих попробовать то, что я уже пробовал, я думаю, что лучше сделать это с самого начала. Прошу прощения, если сообщение получилось длинным.
Давайте попробуем так:
Чего мы пытаемся достичь< /p>
  • Я хочу написать библиотеку, которая вызывает метод известной формы для пользовательских типов.
  • Я хочу этот метод принимает в качестве параметров другие типы, определяемые пользователем.
  • Обе категории этих типов могут иметь любое количество дополнительных методов и пользовательских элементов данных, которые может придумать пользователь.
  • На момент написания библиотеки я не знал подробностей об этих типах.
  • Определения типов мы узнаем во время компиляции.
  • Все эти типы должны содержаться в стандартном типе коллекции, таком как вектор или очередь.
Классическое наследование — попытка 1
В 1990 году я бы делал это с базовыми классами, из которых пользователь извлекает состояния и события, и просил бы их поместить свои пользовательские данные в конкретные классы, дайте мне какой-то механизм определения типов, зарегистрировать их типы в моей библиотеке, используя эти идентификаторы типов, а затем выполнить для них динамическое приведение, когда придет время выполнять обратные вызовы, но я хочу этого избежать.
Мой библиотека предоставит

Код: Выделить всё

class IEvent
{};

class IState
{
public:
virtual void enter(std::shared_ptr event) = 0;
virtual void exit(std::shared_ptr event) = 0;
}
Пользователь определит свои конкретные типы в приложении:

Код: Выделить всё

struct PedCrossingEvent : IEvent
{
int m_customUserData;
};

struct TimerElapsedEvent : IEvent
{
std::string m_othercustomUserData;
};

class GreenState : IState
{
public:
virtual void enter(std::shared_ptr event)
{
// We'd need to perform the dreaded dynamic_cast to get to the concrete type in order to access the user's custom data.
}

virtual void exit(std::shared_ptr event)
{
// We'd need to perform the dreaded dynamic_cast to get to the concrete type in order to access the user's custom data.
}
};
Нам нужно было бы где-то иметь какое-то перечисление или аналогичную систему идентификаторов типов, чтобы пользователь знал, к чему приводить, учитывая интерфейс.
Конечно, я слышал: «Если вы используете Dynamic_cast, дизайн неправильный». Большой! Как нам сделать это прямо тогда? Вы не можете использовать виртуальные методы, чтобы решить проблему незнания того, какие данные пользователь хочет включить в их различные конкретные типы. Если только вы не захотите использовать std::any или void *. Это их путь? Не знаю.
Посетитель – попытка 2
Итак, я немного погуглил и наткнулся на переговоры CppCon по стиранию типов. и шаблон посетителя. «Эй, может быть, это решит мои проблемы!»
Ну, стирание типов позволяет мне помещать любой тип в один и тот же контейнер, поэтому это отвечает одному требованию, но мне все равно нужно знать конкретные типы, чтобы получить определенные пользователем данные, и приведение должно произойти где-то во время или перед вызовом State::enter и State::exit.
Введите шаблон посетителя.< /p>
Рассмотрите следующий листинг кода и представьте, что я пишу библиотеку, которая содержит все, начиная со строки using Event. А типы над этой строкой предоставлены пользователем моей библиотеки. вот лишь минимальный пример того, что я бы делал в коде библиотеки вместо того, чтобы пользователь делал в коде приложения.
Мне нужно сделать вызов чтобы указать::enter и вернуть пользователю тип настраиваемого события в качестве параметра.
Мне нужно сохранить типы настраиваемых событий пользователя в контейнере.
Мне нужно хранить пользовательские типы состояний в контейнере.
Эти типы и их детали неизвестны на момент написания библиотеки. Они универсальны. Однако они будут известны во время компиляции.

Код: Выделить всё

#include 
#include 
#include 

// User defined types examples
struct PedCrossingEvent{int m_myCustomUseData;};
struct ProgramTimeElapsedEvent{double m_myOtherUserCustomData;};
struct NoProgramEvent{std::string m_otherDataStill;};

class Elephant;

struct GreenState
{
Elephant * m_customStateData;

void enter(std::shared_ptr
 predCrossingEvent)
{
if (predCrossingEvent.m_myCustomUseData > 10)
{//...}
}

void enter(std::shared_ptr programTimeElapsedEvent)
{
if( programTimeElapsedEvent.m_myOtherUserCustomData < 100.0 )
{//...}
}

void enter(std::shared_ptr noProgramEvent)
{
if( noProgramEvent.m_otherDataStill< 100.0 )
{//...}
}

void exit(std::shared_ptr pedCrossingEvent)
{}

void exit(std::shared_ptr programTimeElapsedEvent)
{}

void exit(std::shared_ptr noProgramEvent)
{}
};

// How do I, at compile time, register user defined types from above, that could be anything the user dreams up, with this variant in my library?
// I need some kind of "register type" compile time mechanism
using Event = std::variant;

int main()
{
std::vector events = {
std::make_shared(),
std::make_shared(),
std::make_shared()
};

GreenState green;
std::visit([&green](auto&& arg) { green.enter(arg); }, events[0]);

return 0;
}
Демо
Проблема здесь в том, что оператор using должен существовать в моей библиотеке, и я не знаю, какие типы будет использовать пользователь. сделать в будущем. Даже если это будущее действительно будет временем компиляции, а не временем выполнения.
Мне интересно, существует ли какой-то механизм (возможно, магия шаблонов), позволяющий мне взять некоторый список типов, предоставленный пользователем, и зарегистрируйте их, создав std::вариант с использованием этих типов.
В настоящее время я формирую тему вопроса по этому вопросу.
Вниз кроличья нора в забвение
Я могу попытаться обернуть оператор using в шаблонный тип, но мне кажется, что я только перемещаю проблему в другое место. Пользователь все равно должен как-то сообщать мне о типах. Как я могу создать для них метод регистрации, не зная параметров типа?

Код: Выделить всё

/*
* I needed a way to define the variant at compile time without knowing the user defined types
*/
template
class RegisteredEventTypes
{
// Helper to determine if a type is part of the variant
template
struct isVariantMember;

// Helper to determine if a type is part of the variant
template
struct isVariantMember : public std::disjunction {};

public:
using EventVariantType = std::variant;

static constexpr size_t getNumEventTypes()
{
return std::variant_size_v;
}

template
static constexpr bool isTypeRegistered()
{
return isVariantMember ::value;
}
};

int main()
{
// Try out the template.  The user will need to supply this to a registration method, but how can I make such a method without knowing the type params?
using MyEventTypes = RegisteredEventTypes;

// Test that it works
std::cout 

Подробнее здесь: [url]https://stackoverflow.com/questions/78509561/register-types-for-stdvariant-programatically[/url]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»