powered by simpleCommunicator - 2.0.58     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Пятничная шабонная магия
18 сообщений из 143, страница 6 из 6
Пятничная шабонная магия
    #39815310
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Проблема решилась переносом using-ов в хвост класса. Видимо, как-то так работает построитель классов, видимость устанавливается после того, как развернут метод, а не до того. Ну, т.е. можно и до того, но это должен быть готовый метод в классе-предке. А тут его ещё не было.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39815316
Фотография Cerebrum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

если я правильно понял вы хотите использовать класс для хранения значений и извлекать их указывая тип.
В случае если типы хранимых значений внутри класса Param уникальные (а иначе как определить какое именно из 2-х или более значений одинаковых типов нужно извлечь?) то почему не использовать std::tuple ?
Он как раз умеет жранить произвольный состав параметров и извлекать их данные по их типу

и еще

вместо return 0 лучше использовать return {}, поскольку возвращаемое значение не обязательно будет интегральным типом, но также и классом
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39815511
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cerebrum, нет, я хочу хранить множества параметров разных типов в одной коробке.
Сейчас я указываю типы параметров, которые лежат в коробке: <int, float, string> - в качестве параметров шаблона.
- множество типов заранее известно
- количество элементов заранее не известно
- всё на момент компиляции
обычно это классическая задача с одним классом-предком и кучей наследников, тип определяется динамически, в контейнере хранятся указатели на объекты класса-предка. Но я хочу сделать типизацию на момент компиляции, так как мы там знаем, какие типы мы складываем в коробку, почему бы это не использовать сразу?

минусы такие: нету единого итератора, нету порядка
зато есть такой плюс: всё автоматически сортируется по типам


ну и хочется сделать так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
Params<int, float, string> params;
params.ParamAdd ("int", 1); // name, "any" value
params.ParamAdd ("str", "a?");
string srt = params.ParamGet("int"); // returns empty string
string srt = params.ParamGet("str"); // returns "a?"
int iint = params.ParamGet("str"); // returns 0
// т.е. ParamGet без указания типа параметра, который хотим вернуть.
// сейчас надо писать так:
string srt = params.ParamGet<string>("str"); 

ну и там, на самом деле не просто значения, а то, что приходит в ParamAdd, оборачивается в некий класс, который как-то работает с этим параметром (ограничения, жизненный цикл, и прочее)

Cerebrumвместо return 0 лучше использовать return {}это просто заглушка для демонстрации была, там возвращается или параметр-обёртка или значение параметра.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39815797
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Неужели никому не надо?


Ок, у меня получилось. Идея избавления была такая: использовать оператор каста на некотором объекте, который возвращается из ParamGet, когда не указан шаблонный параметр.

Объект в частном случае вышел такой:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
template <typename P, typename... TS> class AnyPass
{};
template <typename P> class AnyPass<P>
{};
template <typename P, typename T1> class AnyPass<P, T1> : public AnyPass<P>
{
public:
	AnyPass(const string name, P* params) { name_ = name; params_ = params; }
	operator T1() { return params_->ParamGet<T1>(name_); }
public:
	string name_;
	P* params_ = nullptr;
};
template <typename P, typename T1, typename... TS> class AnyPass<P, T1, TS...> : public AnyPass<P, TS...>
{
public:
	AnyPass(const string name, P* params) : AnyPass<P, TS...>(name, params) {}
	operator T1() { return *(params_->ParamGet<T1>(name_).get()); }
	operator shared_ptr<T1>() { return params_->ParamGet<T1>(name_); }
};


последний оператор - частный случай, но его можно и оставить, он ничему не противоречит.
получилось даже лучше:

Код: plaintext
1.
2.
3.
4.
5.
6.
		params.ParamAdd("0", 0);
		params.ParamAdd("1.0", 1.0f);
		params.ParamAdd("str", "str");

		float fprm = params.AnyGet("1.0");
		shared_ptr<float> spfprm = params.AnyGet("1.0");


т.е. у меня функция возвращает ровно тот тип, что указан слева, ура!


"лучше", в смысле, у меня тут метод AnyGet, возвращающий "всё", потому что ParamGet через uning проброшен по всей иерархии, и попытки использовать его без шаблона приводят к неоднозначности, а AnyGet должен "быть" только в "последнем" классе:

Код: plaintext
1.
2.
3.
4.
	auto AnyGet(const string& name) -> AnyPass<ParamsAny, TS...>
	{
		return AnyPass<ParamsAny, TS...>(name, this);
	}


(хотя он есть везде, просто невидим)
если кто знает, как это можно сделать одним методом, подскажите :)
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39832552
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
добрый день
где в стандарте почитать про создание и порядок выполнения преобразований, когда используются шаблоны?

ситуация такая у меня
- есть класс std::string
- есть мой класс А, где есть шаблонный оператор (T), кастующий что-то там своё в Т, ок.

теперь, если я напишу так в коде:
Код: plaintext
1.
2.
3.
A a;
string s;
s = a;


я получу ошибку про то, что компилятор не может найти в string оператор = для правого операнда.
явный каст решает проблему
Код: plaintext
1.
s = (string)a;

но это некрасиво (и неудобно, у меня много объектов А и работы с ними, везде писать в коде явные касты нехорошо)

если же я напишу в класса А явный каст:
Код: plaintext
1.
operator string() { return some_string;}


то всё ок

Хмм. Почему в первом случае компилятор не генерит из шаблона оператор для каста в стринг?
А не хочу писать в коде А явный каст, потому что А может работать с любым типом, мне придётся по мере надобности все их вписывать в код, это очень нехорошо.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39832554
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbПочему в первом случае компилятор не генерит из шаблона оператор для каста в стринг?потому что там не стринг.
Помог шаблонный оператор каста в ссылку на T.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833066
a.guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
CEMb
Код: plaintext
1.
2.
3.
A a;
string s;
s = a;



Почему ... компилятор не генерит из шаблона оператор для каста в стринг?
Код: plaintext
1.
2.
3.
4.
5.
basic_string& operator=( const basic_string& str );
basic_string& operator=( basic_string&& str );
basic_string& operator=( const CharT* s );
basic_string& operator=( CharT ch );
basic_string& operator=( std::initializer_list<CharT> ilist );

А почему он должен генерить шаблон для каста в стринг а не в const char* или std::initializer_list<char>?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833185
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a.guestА почему он должен генерить шаблон для каста в стринг а не в const char* или std::initializer_list<char>?ну вот про это и был вопрос.
почему компилятор сначала ищет оператор= слева, а потом оператор string() справа, а не наоборот?
т.е. с int, например, эта конструкция работает. Если бы компилятор поискал у моего класса оператор каста и нашёл бы его, всё собралось бы
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833269
a.guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
CEMbПомог шаблонный оператор каста в ссылку на T.Это как? У меня не помогает.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
#include <string>

struct A {
    template<typename T>
    operator T&();
};

int main()
{
    A a;
    std::string s;
    s = a; // error: use of overloaded operator '=' is ambiguous
}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833276
a.guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
CEMba.guestА почему он должен генерить шаблон для каста в стринг а не в const char* или std::initializer_list<char>?ну вот про это и был вопрос.
почему компилятор сначала ищет оператор= слева, а потом оператор string() справа, а не наоборот?Что значит "сначала" и "потом"?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833614
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a.guestЭто как? У меня не помогает.там надо оба оператора в T и в T&. Я не знаю, почему, хорошо было бы, если бы кто-то объяснил :(

a.guestЧто значит "сначала" и "потом"?
ну вот как там идёт семантический разбор? Я не знаю. Находит выражение "=", потом смотрит, что слева и что справа? У меня в коде 2 варианта, получается
1. искать оператор = у string, который принимает на вход класс А (и не найти)
2. искать оператор string у класса А, чтобы он вернул строку, которая подходит для "=".
где в стандарте написано, что компилятор идёт первым путём?
потому что если я явно указываю каст в string - всё работает, т.е. компилятор идёт вторым путём.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833618
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я тут пытаюсь опять сделать класс, который:
1. можно складывать в контейнеры
2. ему (переменным его типа) можно присваивать и считывать значения разных типов
3. и всё это без динамики и на момент компиляции.

в бусте вроде есть типа Any, не знаю, насколько хорошо и удобно он решает задачу

проблема универсальности в том, что когда мы создаём универсальный класс Param<T>, всё хорошо, до тех пор, пока нам не понадобится складывать его в контейнеры. Потому что контейнеры сразу накладывают ограничение на T. Отнаследовать Param<T> от интерфейса тоже не спасает, так как интерфейс должен иметь метод Get, который возвращает T.
Таким образом, остаётся два варианта:
1. Не использовать шаблоны для Param
2. Написать свой контейнер (как мне кажется - вообще не вариант, потому что надо будет писать все контейнеры, всех итераторы и всё-всё)

вариант 1 подразумевает, что само хранилище значений T должно быть как-то отделено от класса Param, при этом было нарезано компилятором, а не программистом. Мне пришла такая идея: шаблонный метод (назовём Data) со статической мапой внутри. Плюс пара шаблонных методов Set/Get, которые будут ходить в Data, передавая ключ, ссылку на объект и verb, что с этим объектом делать. Кроме того, Set и Get должны аккуратно срезать все модификаторы и ссылки с шаблонного параметра для Data, иначе тот наплодится на каждый тип (int, const int, const int&, int&& и так далее), а нам этого не нужно.
Собственно, "всё хорошо" получилось. Бонусом (ненужным) получилось так, что в одном параметре можно хранить значения разных типов.

Код: plaintext
1.
2.
3.
4.
5.
6.
Param p;
p = 1;
p = "a";
int i = p;
string s = p;
// i = 1, s = "a"


Из чего, собственно, вытекает основная проблема: потеря информации о типе. Изначально я это стал делать для следующей задачи:
- есть большое количество параметров разного типа у объектов
- для объекта надо генерить UI для всех этих параметров (настройка и всё такое).
Вручную рисовать UI под 50 параметров, где ещё всякие надписи и тултипы - не наш путь

И ладно это был бы один класс, но классов много, у них у всех много параметров, и они требуют ещё сериализацию(sql-и пока пишутся вручную) и прочие обработки.
Собственно, информация о типе как раз тут нужна, чтобы знать, какой UI для какого параметра генерить.

Ну и отладка всего этого дела весьма сложна - данные все сидят внутри методов, их просто так не посмотришь.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833623
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbВручную рисовать UI под 50 параметров, где ещё всякие надписи и тултипы - не наш путь
два варианта альтернативных:
1. Именно проектирование руками в дизайнере по ГОСТ конкретной формочки. То есть проектирование. АРМ.
2. Обычно в ГУИ есть контрол типа вертикальный грид. Он по модели сам отображает разные типы в ГУИ. То есть в модели информации о типах и на VIEW просто отрисовка в строках или пикселях.
Имхо
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833642
Фотография Cerebrum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbпроблема универсальности в том, что когда мы создаём универсальный класс Param<T>, всё хорошо, до тех пор, пока нам не понадобится складывать его в контейнеры. Потому что контейнеры сразу накладывают ограничение на T. Отнаследовать Param<T> от интерфейса тоже не спасает, так как интерфейс должен иметь метод Get, который возвращает T.
есть еще третий вариант - идиома Type Erasure .
Если я правильно понял это именно то что вам нужно.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833666
a.guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
CEMba.guestЭто как? У меня не помогает.там надо оба оператора в T и в T&. Я не знаю, почему, хорошо было бы, если бы кто-то объяснил :(Ты не удалил `operator string()`. А T& не при чём.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833682
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cerebrumесть еще третий вариант - идиома Type Erasure .Не, она не подходит под третий пункт, определение всего на момент компиляции, потому что:

HabrПочему RTTI нужно использовать к сожалению? Потому что, хотелось бы написать что-то вроде такого, чтобы перенести проверку типа в compile time:
А у меня эта проверка делается в compile time. Так что я крут


Не, на самом деле, я хорошо себе в голове представляю всю схему со статической типизацией и/или стиранием типа, какие есть архитектурные невозможности (к примеру, если Param не завязан никак на тип принимаемого параметра - это означает автоматом, что именно из Param обратно извлечь тип назад никак не удастся), и тут придётся как-то выбирать одно и отказываться от другого. Например, мне нужна информация о типе параметра для создания UI, я могу просто запоминать тип в отдельную переменную, потому что мне потом будет проще написать функцию разбора списка параметров, основанную на switch-case-ах, чем на шаблонных проверках типа, к тому сам список не имеет отношения к шаблонам.

Про отказ-выбор. Это, так-то, уже второй мой вариант решения избавления от типов в контейнерах. Первый на предыдущей странице, там как раз попытка написать свой "контейнер". И там можно по имени/ключу из контейнера достать параметр, который имеет информацию о своём типе. А можно сразу значение по ключу. Но у той реализации есть свои проблемы, она автоматически сортирует все параметры(рекурсивный шаблон в основе). Она в основе имеет конкретный stl-ный контейнер, если нужно другой - нужно новую реализацию. Она требует в объявлении указать, какие типы будут использованы. У неё нету итераторов по всей коллекции, но можно сделать итераторы по типам(и мне этого хватает там, где оно применяется), и они опять же привязаны жёстко к своим типам. Но как статическая-"динамическая" типизация, вышло неплохо, ящетаю
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39833690
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a.guestТы не удалил `operator string()`. А T& не при чём.ну это в этом примере, а в рабочем коде у меня два шаблонных каста в T и в T&, без них не компилируется :(
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39843834
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YouTube Video
...
Рейтинг: 0 / 0
18 сообщений из 143, страница 6 из 6
Форумы / C++ [игнор отключен] [закрыт для гостей] / Пятничная шабонная магия
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]