Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / C++ Новый топик    Ответить
Топик располагается на нескольких страницах: 1 2 3 4 5 6      [все]
 Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Я надеваю свой шаблонный плащ и шаблонную шляпу...

Была у меня иерархия (классов) на основе вложенности, A содержит вектор объектов B, который в свою очередь содержит вектор объектов С. Всё ок.

Объекты класса C содержали ещё вектор объектов класса D, возможно пустой. Класс D содержал shared_ptr<C>. Чтобы было нагляднее, класс D, это, например, персонаж, а класс C - это клетка карты. Таким образом D всегда находится на какой-то клетке, держит с ней связь через shared_ptr<C>, а клетка содержит в себе список персонажей, которые на ней находятся. Всё ок, всё работало. Тут важный момент про конструкции языка: так как C и D ссылаются друг на друга, то в одном из их заголовков будет упоминание другого.

Но я захотел сделать лучше, захотел сделать слабые связи и масштабируемость. При этом решил воспользоваться шаблонной магией, заклинанием:

template <typename T> class A : public T {};

это породило цепную реакцию шаблонизации всей иерархии классов вплоть до класса A, и там есть ещё 3 обслуживающих класса (тоже шаблоны) которые используют A и друг друга в качестве параметра шаблона. Все эти классы (кто-то ещё раз) ошаблонились. Там тоже есть интересный вопрос по синтаксису, но это всё потом, главное - проблема теперь в C и D. По задумке слабой связанности, С теперь не имеет вектор с D, но есть C1<T>, у которого вектор<T> и функции работы с ним. D теперь без указателя shared_ptr<C>, но есть D1<T> у которого shared_ptr<T> и методы работы с ним.

Всё ок, до тех пор пока не начнёшь всё это создавать, потому что должно быть D1<C1> и C1<D1>, как это сделать? Выше я упоминал, что в случае обычной ссылки друг на друга, один из классов упоминается в заголовке другого и всё хорошо. А как тут быть? Попытался поразбивать C/C1 и D/D1 на иерархии и как-то использовать другие классы в качестве параметров шаблонов, но только всё запутал.

В результате шаблонной магии я вчера развалил себе весь проект напрочь(damage 281 hp per class), т.е. сейчас у меня ни одного работающего класса нет, так как все зависят от D и C.
23 дек 16, 06:34    [20039706]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb
Но я захотел сделать лучше, захотел сделать слабые связи и масштабируемость. При этом решил воспользоваться шаблонной магией, заклинанием:

template <typename T> class A : public T {};


А с чего вы решили, что это хоть как-то устраняет зависимость? )))

CEMb
В результате шаблонной магии я вчера развалил себе весь проект напрочь(damage 281 hp per class), т.е. сейчас у меня ни одного работающего класса нет, так как все зависят от D и C.

Так всегда бывает, когда не к месту применяешь заклинания )))
23 дек 16, 10:43    [20040344]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Пётр Седов
Member

Откуда: Санкт-Петербург
Сообщений: 674
CEMb, умные указатели -- это неуклюжая попытка превратить C++ в подобие managed-языка. При разработке игр на C++ это не особо нужно.
24 дек 16, 03:44    [20044004]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 34548
CEMb
[i]

Была у меня иерархия (классов) на основе вложенности, A содержит вектор объектов B, который в свою очередь содержит вектор объектов С. Всё ок.

.


что уж тут ок? иерархия (классов) на основе вложенности - это как-то странно, это не ок...
24 дек 16, 09:41    [20044128]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 34548
CEMb
[i. Тут важный момент про конструкции языка: так как C и D ссылаются друг на друга, то в одном из их заголовков будет упоминание другого.
.


ничего подобного, если они просто ссылаться друг нам друга, то в их реализации достаточно знать определение каждого из партнеров, но в объявления классов достаточно сделать лишь forward declaration другого класса, в виде

class D;

никакая шаблонная магия тут не нужна.
24 дек 16, 09:48    [20044133]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky
А с чего вы решили, что это хоть как-то устраняет зависимость? )))
Изначальные классы друг о друге ничего не знают.
Пётр Седов
CEMb, умные указатели -- это неуклюжая попытка превратить C++ в подобие managed-языка. При разработке игр на C++ это не особо нужно.
Умные указатели тут ни при чём, я мог бы использовать что-то другое для связи, это ситуацию не меняет, вопрос же был не про это А игры тут при чём? Как игры или не игры влияют принципиально на разработку?
MasterZiv
что уж тут ок? иерархия (классов) на основе вложенности - это как-то странно, это не ок...
Ну не иерархия, а зависимость, всё равно всё ок. Иерархия - логическая, т.е. элементы одного класса являются частью другого (членами класса). Иерархия получается логическая.
MasterZiv
достаточно сделать лишь forward declaration другого класса, в виде
Ну я это и имел ввиду, когда говорил об упоминании.
MasterZiv
никакая шаблонная магия тут не нужна.
Почему никто не читает то, что я пишу шаблонная магия нужна была для построения двух как можно более независимых иерархий классов. Это необходимо для более удобной разработки, когда мне надо будет менять базовые элементы в обоих иерархиях. Сейчас зависимости между двумя иерархиями явно присутствуют в классах, это неудобно.
26 дек 16, 05:40    [20047346]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
mayton
Member

Откуда: loopback
Сообщений: 43427
А можно пример использования? Чтобы почувствовать всю "крутость" и "загадочность" этой магии.
26 дек 16, 10:00    [20047726]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
mayton
А можно пример использования? Чтобы почувствовать всю "крутость" и "загадочность" этой магии.
ага, если речь про
template <typename T> class A : public T {};
то тут всё просто. Данная конструкция делает надстройку над классом, к которому применяется. Применений тут много, я хочу использовать увеличение информации внутри класса. Есть класс А:
class A {
};
делаем шаблон:
template <typename T> class CUID : public T {
	unsigned int uid_ = 0;
public:
	unsigned int UIDGet() const {return uid_;}
	void UIDSet(unsigned int uid) {uid_ = uid;} 
};
после этого мы можем делать так:
CUID<A> auid; - Объект с функционалом класса А и с уидами. При этом ни А ничего не знает про CUID, ни CUID ничего не знает про A и эти два класса могут разрабатываться независимо.
Мы можем вешать CUID на любые классы: CUID<B> - это отличие от наследования, где если мы хотели добавить uid в дочерний класс и отнаследовались - чтобы навешать uid на другой класс, нам надо заново наследоваться (это грубое сравнение, в реальной жизни, само собой, мы бы по-другому сделали). Тут же достаточно просто в объявлении объекта указать CUID чтобы получить дополнительный нужный функционал. Ногами не пинайте, если вдруг рассказываю понятные вещи, я обычно всегда стараюсь подробно всё рассказывать.
"Магия" у меня там в проекте заключалась в том, что я хотел таким образом развести независимо 3 иерархии классов, которые у меня были изначально связаны друг с другом, чтобы потом можно было разрабатывать их независимо. Шаблонизацию я закончил, осталось сделать правильные объявления. Надеюсь.
26 дек 16, 13:59    [20048929]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 34548
CEMb
MasterZiv
никакая шаблонная магия тут не нужна.
Почему никто не читает то, что я пишу шаблонная магия нужна была для построения двух как можно более независимых иерархий классов. Это необходимо для более удобной разработки, когда мне надо будет менять базовые элементы в обоих иерархиях. Сейчас зависимости между двумя иерархиями явно присутствуют в классах, это неудобно.


Для этого шаблонная магия тоже не нужна.
Для этого нужны классические паттерны, к которым шаблонная магия никак не относится.
Итого, у меня уже вырабатывается чёткое подозрение, что ты вообще что-то не то делаешь, что следовало бы.
Но что тебе нужно, я до конца не понял, так что думай сам.
26 дек 16, 14:23    [20049052]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
egorych
Member

Откуда: и зачем;
Сообщений: 4770
MasterZiv
Для этого шаблонная магия тоже не нужна.
Для этого нужны классические паттерны, к которым шаблонная магия никак не относится.
Итого, у меня уже вырабатывается чёткое подозрение, что ты вообще что-то не то делаешь, что следовало бы.
Но что тебе нужно, я до конца не понял, так что думай сам.
ну, ТС пусть читает Александреску, он как то же крестил ежа с ужом, собирал патерны на шаблонах.
Так то я вот тоже не понимаю, что человек задумал, но вдруг чем то ему поможет
26 дек 16, 14:55    [20049221]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Пётр Седов
Member

Откуда: Санкт-Петербург
Сообщений: 674
CEMb
Пётр Седов
CEMb, умные указатели -- это неуклюжая попытка превратить C++ в подобие managed-языка. При разработке игр на C++ это не особо нужно.
Умные указатели тут ни при чём, я мог бы использовать что-то другое для связи, это ситуацию не меняет, вопрос же был не про это А игры тут при чём?
Прочитал вот это:
CEMb
Чтобы было нагляднее, класс D, это, например, персонаж, а класс C - это клетка карты. Таким образом D всегда находится на какой-то клетке, держит с ней связь через shared_ptr<C>, а клетка содержит в себе список персонажей, которые на ней находятся.
...
damage 281 hp per class
и подумал, что речь идёт о разработке игры. А то по именам типа «A», «B» сложно понять, что происходит.

CEMb
Как игры или не игры влияют принципиально на разработку?
Если игровую логику пишут на C++, то значит хотят выжать максимум из железа (по скорости и по памяти), а значит умные указатели лучше не использовать. std::shared_ptr выделяет блок памяти, в котором хранит счётчик ссылок и deleter.
27 дек 16, 01:10    [20051054]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
MasterZiv
Для этого шаблонная магия тоже не нужна.
Для этого нужны классические паттерны, к которым шаблонная магия никак не относится.
какие?
egorych
ну, ТС пусть читает Александреску, он как то же крестил ежа с ужом, собирал патерны на шаблонах.
ну вот я как раз его и читаю.
Пётр Седов
Прочитал вот это:
так я и говорю, чтобы было нагляднее :)
Пётр Седов
Если игровую логику пишут на C++, то значит хотят выжать максимум из железа (по скорости и по памяти), а значит умные указатели лучше не использовать.
наверно, получается так. Хотя не уверен, что работа в играх с каким-то внутреигровыми объектами на shared_ptr съест ресурсы железа соразмерно с той же графикой.
27 дек 16, 05:22    [20051165]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
В общем, получилось как-то так:

// base class A
class CA {
};

// AEx with gypotethic B
template <template <typename CA>, class BI> class CAWithB : public CA {
vector<BI<CAWithBI>> m_vb;
};

//base class B
class CB {
};

// BEx with gypothethic A
template <typename AI> class CBWithAI : public CB {
AI *m_pA;
}

// code
CAWithBI<CBWithAI> a;

CAWithB ждёт в качестве параметра шаблон и скармливает этому шаблону в виде параметра себя. CBWithAI ждёт на вход класс и получает его внутри CAWithB поэтому при объявлении переменной шаблонный параметр явно указывать не надо, он берётся из шаблона, в который этот шаблон передали параметром.

Ну как, стал я шаблонным магом 2-го уровня? о_о
29 дек 16, 07:58    [20058755]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
решил я зайти с другой стороны.
т.е. первая сторона: при объявлении переменной шаблонного класса мы передаём в шаблон все базовые типы и шаблоны используемых классов, и потом в этом шаблоне раздаём типы всем шаблонным-шаблонным параметрам. Это всё хорошо и правильно, потому что это гарантия использования одних типов во всех используемых классах.
другая сторона: шаблон, который должен знать только про один входящий обслуживаемый класс, при этом иногда должен возвращать или работать с типами, с которыми работает этот обслуживаемый класс-параметр. Если более детально, то в первом случае мы инициализируем всё в рамках одной переменной, а во втором, эту переменную(этот тип) используем для создания сервисного объекта. Вот тут тонкое место про типосовместимость: нам по-хорошему не надо заводить в шаблоне параметры для базовых типов, используемых в первом случае, просто потому что есть возможность там задать другие типы. У меня в результате так и получилось: пока я разрабатывал, я в шаблон добавил просто родительские классы, а потом при компиляции "оказалось", что типы этих классов не совпадают с типами классов, с которыми работает обслуживаемый класс.
Ок, поэтому во втором случае полезно передавать только основной класс в шаблон и из него как-то получать типы, с которыми работает этот класс. Если мы работаем как транслятор или посредник-обработчик, т.е. вызываем функции базовых классов или передаём данные базовых типов из обслуживаемого класса наружу, то auto подходит великолепно. Но вот если нам нужны какие-то переменные базовых типов внутри класса, то auto уже не подходит. Я решил использовать decltype. При этом, так как у меня из обслуживаемого класса доступны только функции, можно написать decltype(&f()) и получить тип. И тут у меня два вопроса
1. если функция возвращает shared_ptr<T>, то как из этого типа выдернуть T?
2. почему я не могу сказать decltype(&f()) если f - private или protected? sizeof вроде в таких случая работает.
20 янв 17, 07:08    [20125380]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
CEMb
1. если функция возвращает shared_ptr<T>, то как из этого типа выдернуть T?
decltype(foo.get()); же...
20 янв 17, 07:17    [20125388]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
ermak.nn
Member

Откуда: Нижний Новгород
Сообщений: 55
CEMb
CEMb
1. если функция возвращает shared_ptr<T>, то как из этого типа выдернуть T?
decltype(foo.get()); же...

Вернет T*, нужно хотя бы decltype(*foo)
Вам не поможет element_type? Т.е. foo.element_type
20 янв 17, 10:26    [20125879]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
ermak.nn, да, конечно, я просто навскидку написал общую идею. Спасибо.

вообще, если полностью, то это выглядит так:

template <typename T0> A0
{
protected:
	static T0& __typer () { ststic T0 t; return t;}
};

template <typename T>class A : public T
{
public:
	using TYPE = typename std::remove_reference<decltype(*&A0::__typer())>::type;
};

таким образом TYPE для внешнего наблюдателя это T0, если A<A0<T0>>::TYPE. Но:
1. криво как-то выглядит...
2. всё-таки есть сомнения в идеологической правильности такого подхода
20 янв 17, 11:31    [20126260]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Доработал идею полностью на шаблонах сегодня утром, хочется немного высказаться Картинка с другого сайта.
Для простоты понимания, значит, иерархия была такая, по аналогии:
1. Библиотека - шкаф - книга - страница.
2. Закладка.
3. Поиск.
4. Консоль.
Это всё просто аналогии, на самом деле всё абстрактно. Это важно.

Изначально шаблонов не было, иерархия №1 была "классической": в библиотеке шкафы, в шкафах книги, в книгах страницы. Закладка могла указывать на страницу, на одной странице могло быть различное (0..N) число закладок. Само собой, когда я делал иерархию №1, я сделал интерфейс книги так, что можно получить страницу по номеру. Потом, когда я делал шкаф, я сделал интерфейс для получения книги по названию, ну и, для удобства по названию книги и номеру страницы - страницу из шкафа. В аналогии звучит весело, но когда на руках абстрактные классы, это вроде как нормально и удобно. Ок. С библиотекой в результате получилось тоже самое: по номеру шкафа, названию книги и номеру страницы из библиотеки можно сразу получить страницу.

С закладками всё немного не так, как в жизни, закладке пришлось-таки помнить своё место от шкафа до страницы, иначе смысл такой закладки терялся. Но вернёмся к первой иерархии. Когда я стал её переводить на шаблоны, названия классов выросли до 3 экранов. Почему так. Библиотека должна была знать классы шкафа, книги и страницы, чтобы уметь возвращать объект страницы. При этом явно указывать ни один из этих классов нельзя, они все идут как параметры шаблона, итого 3 (на самом деле 4, ещё и закладки, но это потом). Далее, класс шкафа должен так же уметь работать с книгами и страницами, которые тоже должны быть параметры его шаблона. Шаблона. Вот теперь делаем шаг назад и в шаблоне библиотеки заменяем первый шаблонный параметр (шкаф) этим самым шаблоном шкафа. Тоже самое проделываем с книгой, но ещё и в шаблоне шкафа заменяем первый параметр, книгу, на шаблон книги. В результате у нас получается прикольная иерархия шаблонов, которые внутри себя передают свои параметры друг другу. Название класса библиотеки почти влазит в один экран. Ура.

И вот теперь надо добавить закладки. Закладка по сложности описания почти доходит до библиотеки, потому что у неё в параметрах тоже шкаф, книга и страница. Но при этом посмотрим на первую иерархию, там тоже должна появится закладка, как минимум в классе библиотеки и в классе страницы. А так как страница фигурирует в книге и шкафу, то и там тоже. Страница превращается в шаблон с параметром "закладка" и этот шаблон в качестве параметра заменяет класс в шаблонах библиотеки, шкафа и книги.

Если вы ещё со мной, то вернёмся к закладке: у неё в качестве параметров должны добавляться шкаф, книга и страница. При этом они должны быть идентичны по (шаблонной)сигнатуре параметрам в первой иерархии. Но шкаф, книга и страница сами принимают на вход шаблон закладки. Рекурсия :) Но задача решается применением магии 20058755, описанной выше, но более сложной. Там 2 класса, тут класс + иерархия 3 классов, все друг на друга ссылаются. Нагрузку по прокидыванию себя в шаблонные параметры я оставил в закладке, так как иерархия №1 и так была перегружена магией.

Если до этого всё было более-менее понятно, до дальше шли пункт 3 и 4. Это тоже должны были стать 2 шаблона, первый принимал в качестве параметра библиотеку, второй принимал на вход библиотеку и поиск. Т.е. из консоли должно было возможно делать поиск в библиотеке, грубо говоря. И вот тут я стал запутываться, так как шаблонный параметр библиотеки в обоих этих классах тоже должен был быть шаблоном, причём ровно таким многоэтажным, каким он был в иерархии №1. Почему так: поиск и консоль должны были уметь возвращать, например, страницу по закладке. Т.е. класс страницы там должен был как-то появиться, чтобы поиск и консоль могли с ним работать.

На самом деле я всё писал не в такой последовательности, просто потому что изначально всё было уже написано без шаблонов, а потом я пытался всё и сразу перевести на шаблоны. И проблемы начались где-то по середине, когда я пытался свести все шаблоны к нужному виду, чтобы они нормально принимались в качестве параметров другими шаблонами, опять рекурсия. А надо ещё учесть, что у всех шаблонов были родительские классы, с информацией. Шаблоны, по моей задумке, нужны были для связи. Поэтому для простоты я ввёл порядок в описание, чтобы было нагляднее.

И вот когда в понедельник с утра я понял, что всё слегка запуталось, я сел и посмотрел на иерархию №1. И вот тогда я решил выкинуть все транзитные взаимосвязи. В библиотеке только шкафы, в шкафах только книги, а в книгах страницы. И сразу куча "кода" из названий классов пропала, во-первых. Во-вторых, я разбил классы библиотеки на отдельные шаблоны-прослойки, которые просто работали с транзитными данными, принимая в качестве шаблонных параметров только родителя и только целевой тип. Например библиотека_с_книгами<библиотека, книга>который, например, просто по названию возвращает просто книгу(из auto шкафа, см. далее). Код упростился и распался на несколько никак не зависящих частей. Они все наследовались один раз, при декларации класса(шаблона), и потом про них можно забыть. Точно так же выкинул упоминания класса страницы из шаблона шкафа, и часть кода сразу можно было выкинуть(она "волшебным образом" оказалась уже в прослойках для класса библиотеки).

Вот тут вылезла польза auto. Если раньше я считал его просто удобным иногда, а часто вредным из-за нечитаемости кода, тот тут оно просто стало необходимым. Изначально библиотека ведает только о шкафах. Абстрактная прослойка, работающая с книгами, ничего про класс шкафов не знает, но имеет доступ к родительским методам для работы с ними. Поэтому auto для определения типа, возвращаемого методом родительского класса - самое оно! Пришлось местами переписать функции, чтобы они именно возвращали объекты. Не знаю, хорошо это или плохо. Раньше они возвращали bool, теперь кидают исключение.

Но смотрите, я мог и не делать эти прослойки тут. Основной бонус, к которому меня подтолкнули шаблоны - разрыв связей, и это мне удалось по максимуму. Вот эти код-прослойки я могу делать прямо внутри классов поиска и консоли: я могу написать там тот же код на auto для получения нужных объектов нужных классов и потом получения их дочерних объектов и так далее. Или могу отнаследовать входящий шаблонный параметр библиотеки от готового кода прослойки. Неважно. Главное у меня теперь есть дважды независимый код, который можно использовать на конкретных объектах, о которых он ничего не знает (кроме названий функций). Главным уроком было то, что когда я переписал "нормальный" код на шаблоны, сразу стало видно, что он совсем не нормальный, и сразу стало видно, как надо сделать правильно.

В результате у меня семь файлов(4+1+1+1) с описанием независимых друг от друга классов, без forward declaration, их можно разрабатывать отдельно, что и было целью моего приключения: я хотел иметь возможность фиксировать эти классы на некоторых моментах разработки, а потом мочь заменять их другими с более широким или просто иным функционалом, при этом чтобы другие работали как прежде, а так же мочь возвращаться к прежним классам, если нужно. И теперь я это могу, просто заменив название одного класса на другой в строке декларации объекта :)

И дайте мне уже мой чёртов второй уровень шаблонной магии
24 янв 17, 08:45    [20138085]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb,

Ваша ошибка в том, что вы вместо описания конкретной предметной области пытались в первом посте объяснить все какими-то абстрактными сущностями A B C.
Если бы вы сразу написали про книги, то вам бы сразу и сказали что в сущности Страница не должно быть никакой ссылки на сущность Закладка. И никаких бы циклических ссылок не было бы ))
24 янв 17, 15:26    [20140439]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky
Ваша ошибка в том, что вы вместо описания конкретной предметной области пытались в первом посте объяснить все какими-то абстрактными сущностями A B C.
Если бы вы сразу написали про книги, то вам бы сразу и сказали что в сущности Страница не должно быть никакой ссылки на сущность Закладка. И никаких бы циклических ссылок не было бы ))

Нет никакой ошибки. Предметную область я добавил в описание для того, чтобы было легче понять логическую связь между классами. Выше я приводил пример с картами. Если писать про А, В, С, никто читать не будет, потому что потеряется на втором абзаце :) читать и одновременно строить и держать в голове абстрактную модель в общем случае тяжело для человека.
Сделать ссылающиеся друг на друга и при этом независимые шаблоны - это была цель. Как альтернатива избавлению от связей в коде. По-моему, получилось отлично: никаких #include, forward declaration, интерфейсов, собирается на момент компиляции. Лучше не бывает!
Где мой диплом шаблонного мага? :) я уже придумал ТЗ на новое заклинание для получения 3-го уровня.
25 янв 17, 05:23    [20142570]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Я надеваю свой шаблонный плащ и шаблонную шляпу...

Статическая альтернатива polymorphic hell

Вчера вечером натолкнулся на такую проблему:
- Есть некое множество классов, назовём их Shape, у которых есть метод Compare, который на вход принимает ссылку на другой объект Shape.
- Есть некий класс А, который должен содержать вектор этих самых Shape. У А есть тоже метод Compare, который на вход принимает ссылку на А.
- В А::Compare нужно все родные Shape "сравнить" через Compare входящего объека А. При этом если классы родного Shape и входящего Shape не совпадают - делать ничего не надо. Строгая типизация, типа.

Сначала я сделал так: все классы Shape отнаследовал от одного базового, скажем ShapeBase, метод Compare сделал виртуальным, в классе А завёл вектор ShapeBase и в методе А::Compare устроил двойной цикл сравнения "каждый с каждым".

Но тут обнаружилась проблема: строгая типизация. Нужно было на ходу извлекать реальные типы из итераторов ShapeBase. При условии, что А::Compare должен отрабатывать так быстро, как только можно, методы динамического определения типов оказались плохим вариантом. Так как долго.

В результате я опять решил всё сделать на шаблонах. Проблема была в том, что вектор в А должен содержать объекты разных классов. Я решил сделать шаблон, с двумя параметрами, один - базовый класс A, второй - класс Shape, вектор которого я объявил внутри шаблона.
template <typename P, typename S> class Shaper : public P
{
         std::vector<S> m_vS;
public:
         bool Compare(const Shaper&);
         void AddShape(S&& s);
};

Ok, добавляя этот шаблон к А(через параметр P), я получал для одного класса Shape то, что требовалось.

Теперь надо чтобы можно было добавить в структуру второй шаблон. Параметр Р тут как верёвочка, на которую нанизываются шаблоны. Если теперь просто навесить сверху второй Shape, он так же удачно заработает, но отвалится первый, его методы Compare и AddShape перестанут работать, так как они перекрыты вторым шаблоном, и их не будет видно.
Проблема решается через добавление
using S::Compare;
using S::AddShape;

Теперь при добавлении объектов Shape1, Shape2 и так далее, все они складываются в свои вектора. Ура.
Осталась одна проблема: базовый класс А. Он должен поддержать то, что написано в using. Туда достаточно добавить минимальные заглушки (шаблону в большей степени всё равно), и вся иерархия становится завершённой(в решении я вынес это в отдельный шаблон, чтобы не мусорить в А). Compare потребуется указать параметр, так как он будет зваться рекурсивно, а вот AddShape всё равно на параметры, он зовётся только снаружи.

Минусы:
- заведение закрывающего класса Shaper. Хотя в обычном варианте так же присутствует "лишний" класс - основа иерархии.
- если в иерархии А были явные конструкторы с параметрами - придётся их пробросить в Shaper и P.
- обработку (обход) по вектору придётся вынести в сами методы шаблона Shaper, для рекурсии. А это даже уже плюс.
- "вектор" объектов нельзя сортировать/перестраивать как угодно, сложно (но реализуемо) обращение по индексу.
- объявление типа конечного класса занимает много места :)

Плюсы:
+ скорость обхода "вектора" на порядок меньше, чем в классическом варианте: количество итераций пропорционально N против N2 в случае с полным обходом.
+ статическая типизация. И нет virtual.
+ "вектор" "отсортирован" автоматически - как бы мы ни добавляли элементы в "вектор", при обработке они пойдут порядке объявленных в шаблоне классов. Плюс сомнительный, скорее просто фича.
+ все классы Shape и класс А - независимы друг от друга, все связываются через Shaper
+ изначальный код класса А ничего не знает про новый функционал, связанный с классами Shape. Если заглушки вынести в отдельный класс, то код класса А вообще не меняется. Так ж класс Shaper ничего не знает про класс А.

В общем случае такой подход не применим, но в моём варианте отлично подходит.

+ Ну и вот простенький примерчик, для наглядности
class Shape1
{
         int m_iData;
public:
         void Draw() { printf("S1> \n"); }
};

class Shape2
{
         int m_iData;
public:
         void Draw() { printf("S2> \n"); }
};

class ShapeStubs
{
public:
         void DrawAll(){};
         void AddShape(){};
};
 
template <typename P, typename S> class CStaticPoly : public P
{
         std::vector<S> m_vS;
public:
         using P::DrawAll;
         void DrawAll();
         using P::AddShape;
         void AddShape(S&& s);
};

template <typename P, typename S> void CStaticPoly<P, S>::DrawAll()
{
         for (auto s : m_vS)
                 s.Draw();
         P::DrawAll();
}

template <typename P, typename S> void CStaticPoly<P, S>::AddShape(S&& s)
{
         m_vS.emplace_back(s);
}

int _tmain(int argc, _TCHAR* argv[])
{
         CStaticPoly<CStaticPoly<ShapeStubs, Shape1>, Shape2> c;
         c.AddShape(Shape1());
         c.AddShape(Shape2());
         c.AddShape(Shape1());
         c.AddShape(Shape2());
         c.DrawAll();

         return 0;
}


Мне было бы так же интересно, как можно было бы быстро решить эту задачу классическим методом. Но только не добавляя в классы Shape информацию о типе! :)
2 фев 17, 11:54    [20172805]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
...
- а я написал игру, используя шаблоны
- ну и как игра?
- победил на этапе компиляции...


---
Возникла такая ситауация: у меня есть шаблон, который принимает на вход шаблонные-шаблонные параметры. В процессе реализации мне захотелось абстрагировать один фундаментальный тип (это был float) на что-то общее, потому что тип иногда даёт ошибки вычисления, да и вообще есть задачи, которые должны решаться снаружи этого типа (функции, константы). Поэтому решено было заменить тип классом, шаблонным, само собой, но это не важно. Важно то, что тип (float) плотно использовался в одном из шаблонных-шаблонных параметров А. А это значит, что в шаблон этого шаблонного-шаблонного параметра А нужно будет добавить ещё один typename и то же самое учесть во всех зависимых от него шаблонах, а это большая переделка.

для начала я вынес всю работу с float в отдельный шаблон:
template <typename B> class A {};
template <typename B, typename M> class A1 : public A<B> {};

в таком виде A1 непригоден для использования, так как по сигнатуре не подходит под А

поэтому непосредственно перед использованием-объявлением я написал строчку:
template <typename B> class A2 : public A1<B, Metric<float>>
using BarType = Bar <... ,A2, ...>;

так вот вопрос: можно ли как-то обойтись без А2? Как-то в идеале примерно так:
using BarType = Bar <... ,A1<Metric<float>>, ...>;

т.е. в результате должен получиться шаблон с одним входящим параметром. Понятно, что в таком "объявлении" неясно, какой из двух параметров указан, поэтому и вопрос, есть ли какие инструменты в языке, которые позволяют в одной строке указать один из параметров шаблона?

Сообщение было отредактировано: 7 фев 17, 13:07
7 фев 17, 12:55    [20188416]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
CEMb
Статическая альтернатива polymorphic hell
Всё можно сделать в разы проще:
template <typename... Ts> class CStaticPoly;
template <> class CStaticPoly<>
{
public:
         void Add(...) {}
};

template <typename T1, typename... Ts> class CStaticPoly<T1, Ts...> : public CStaticPoly<Ts...>
{
         std::vector<T1> m_v;
public:
         using CStaticPoly<Ts...>::Add;
         void Add(T1&& t1) { m_v.emplace_back(t1); }
         void Draw() {}
};
//... in far-far galaxy:
CStaticPoly <Shape1, Shape2> c;
c.Add(Shape1());
c.Add(Shape2());
почему никто не сказал?
2 мар 17, 08:32    [20256178]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb
почему никто не сказал?

Потому что никто не читает и тем более не улучшает абстрактный код делающий непонятно что
2 мар 17, 13:54    [20257497]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky
Потому что никто не читает и тем более не улучшает абстрактный код делающий непонятно что
Тема ветки - про изучение шаблонов, я хочу сильно преуспеть на этом поприще. Далее, я два раза придумывал тематические объяснения для структур данных, чтобы было удобнее понимать. И я как раз упомянул, что описание - чтобы было удобно читать не про абстракции.
Последние два поста про формирование блока объектов внутри класса. Никто же не жалуется, что vector<T> - ни о чём? Или паттерны программирования. Тут та же ситуация, я пытаюсь на шаблонах сделать иерархию классов, цель указана три поста назад: 20172805, но и то, у меня там в качестве примера приведена ситуация собирания и рисования двух классов объектов.
2 мар 17, 20:10    [20258722]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
я тут пару раз уронил компилятор(ms vc++2013), "внутренняя ошибка, поменяйте строки местами...", и у меня возник вопрос.
можно как-то (ключи?) посмотреть логи сборки, процесс компиляции, в общем, более развёрнуто увидеть причины ошибок?
7 мар 17, 08:45    [20269515]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Siemargl
Member [заблокирован]

Откуда: 010100
Сообщений: 6330
CEMb,
http://stackoverflow.com/questions/9016111/to-see-all-command-line-on-output-window-while-compiling
http://stackoverflow.com/questions/1211841/how-can-i-make-visual-studios-build-be-very-verbose
7 мар 17, 12:48    [20270675]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
А кто знает самый просто способ выдернуть тип шаблонного параметра из класса?

template<typename T> class C
{};

//...
int main
{
	C<A> c;
	// как извлечь из с имя класса А правильным и желательно простым-красивым способом?
}
11 май 17, 13:32    [20472435]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
NekZ
Member

Откуда: Stuttgart, Baden-Württemberg.
Сообщений: 3568
CEMb
А кто знает самый просто способ выдернуть тип шаблонного параметра из класса?

template<typename T> class C
{};

//...
int main
{
	C<A> c;
	// как извлечь из с имя класса А правильным и желательно простым-красивым способом?
}

Я знаю только об одном способе
template<typename T> class C
{
public:
   using Type = T;
};

//...
int main
{
	C<A> c;
	typename decltype(c)::Type t;
}
11 май 17, 13:35    [20472457]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
NekZ, о, спасиб, я до этого пользовался таким: 20126260

Btw, у меня проблема

Общий смысл: сделать двух-связанный список классов, по такому принципу:
1. Класс А содержит массив объектов класса В
2. Класс В содержит указатель на объект класса А, в массив которого он входит.
Ну и всё на шаблонах, чтобы можно было сложную иерархию классов написать просто:
M<L<S<P>>>  m; // M содержит массив L, содержащий массивы S, содержащие массивы P
//и любой элемент этих классов содержит weak_ptr на родителя
шаг первый был прост, передаём класс B в качестве параметра в шаблон А и там заводим на него массив, ок.
шаг второй был сложнее, так как при правильной передаче всех шаблонных параметров в обе стороны, описания классов (да просто первая строка декларации) разрастались в геометрической прогрессии. Поэтому оставался один вариант: при создании массива внутри класса, класс сам сообщает его элементам себя в качестве родительского. Это очень компактно и не растягивает декларации классов. Всё ок, но только в случае, если классов два. Дело в том, что в вше приведённом объявлении, класс S передаёт себя в качестве родителя в класс P, но сам он ещё ничего про класс L не знает. И вот, получив родителя с элемента класса P, мы не сможем с него вызвать GetParent.
+ вот что получилось

template <typename T, typename PR> class CH : public T  // хитрый план
{
                shared_ptr<PR> m_parent;
public:
                CH(const shared_ptr<PR>& parent) { m_parent = parent; }
                shared_ptr<PR> GetParent() const { return  m_parent; }
};

template <typename L> class M : public enable_shared_from_this<M<L>>
{
public:
                using LL = CH<L, M>; // применение хитрого плана
private:
                vector<shared_ptr<LL>> m_children; // использование применения хитрого плана
public:
                shared_ptr<LL> Add() { m_children.emplace_back(make_shared<LL>(shared_from_this())); return m_children.back(); }
};

template <typename S> class L
{
public:
                using SS = CH<S, L>; // применение хитрого плана
private:
                vector<shared_ptr<SS>> m_children; // использование применения хитрого плана
public:
                shared_ptr<SS> Add() { m_children.emplace_back(make_shared<SS>(shared_from_this())); return m_children.back(); }
};

template <typename P> class S
{
public:
                using PP = CH<P, S>; // применение хитрого плана
private:
                vector<shared_ptr<PP>> m_children; // использование применения хитрого плана
public:
                shared_ptr<PP> Add() { m_children.emplace_back(make_shared<PP>(shared_from_this())); return m_children.back(); }
};

class P
{
};

// somewhere in main
                M<L<S<P>>>  m;
                auto l = m.Add();
                auto s = l->Add();
                auto p = s->Add();
                auto s2 = p->GetParent();
                auto l2 = s2->GetParent(); // <- here's the problem
второй день не могу придумать, как малыми силами это победить
19 май 17, 08:12    [20494683]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
                M<L<S<P>>>  m;
                auto l = m.Add();
                auto s = l->Add();
                auto p = s->Add();
                auto s2 = p->GetParent();
                auto l2 = s2->GetParent(); // <- here's the problem

Причём, s2 и s - это один и тот же объект в памяти, но s->GetParent() нормально работает. При этом в коде нету виртуальности. Как уболтать компилятор?
22 май 17, 13:55    [20501275]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
...
Кольцо Всевластия несомненно было шаблоном: работало исключительно согласно классу персонажа, которого в него передавали...


Сделал двойным проходом:
template <typename S> class P2
{
};
template <typename L, typename P> class S2
{
};
template <typename M, class S> class L2
{
};

template <class L> class M : public enable_shared_from_this<M<L>>
{
         vector<shared_ptr<L>> m_vl;
public:
         shared_ptr<L> Add() { m_vl.emplace_back(make_shared<L>(shared_from_this())); return m_vl.back(); }
};
 
template <class S> class L : public L2 <M<L<S>>, S>, public enable_shared_from_this<L<S>>
{
         weak_ptr<M<L<S>>> m_parent;
         vector<shared_ptr<S>> m_vs;
public:
         L(const shared_ptr<M<L<S>>>& parent) { m_parent = parent; }
         shared_ptr<M<L<S>>> GetParent() const { return m_parent.lock(); }
         shared_ptr<S> Add() { m_vs.emplace_back(make_shared<S>(shared_from_this())); return m_vs.back(); }
};
template <class P> class S : public S2 <L<S<P>>, P>, public enable_shared_from_this<S<P>>
{
         weak_ptr<L<S<P>>> m_parent;
         vector<shared_ptr<P>> m_vp;
public:
         S(const shared_ptr<L<S<P>>>& parent) { m_parent = parent; }
         shared_ptr<L<S<P>>> GetParent() const { return  m_parent.lock(); }
         shared_ptr<P> Add() { m_vp.emplace_back(make_shared<P>(shared_from_this())); return m_vp.back(); }
};
class P : public P2<S<P>>
{
         weak_ptr<S<P>> m_parent;
public:
         P(const shared_ptr<S<P>>& parent) { m_parent = parent; }
         shared_ptr<S<P>> GetParent() const { return  m_parent.lock(); }
};

// somewhere in far-far main
shared_ptr<M<L<S<P>>>> m = make_shared<M<L<S<P>>>>();
 
auto l = m->Add();
auto s = l->Add();
auto p = s->Add();
auto s2 = p->GetParent();
auto l2 = s2->GetParent();
auto m2 = l2>GetParent();
немного громоздко получилось местами, но, думаю, можно причесать по двум направлениям
чувствую себя перешедшим на третий уровень, хотя что такое цифры в понятиях шаблонного мага...

PS: если вы не пишите ответы, то закидывайте сюда хотя бы интересные вопросы/код/задачки, касающиеся шаблонной магии Картинка с другого сайта.
25 май 17, 12:00    [20510760]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Натолкнулся на такую проблему, есть два класса:

template <template <typename B> class A> class B1
{
         weak_ptr<A<B1>> _a;
public:
         B1(shared_ptr<A<B1>> a){ _a = a; }
private:
};

template <typename B> class A1 : public enable_shared_from_this<A1<B>>
{
protected:
         shared_ptr<B> _b;
public:
         A1() {}
         virtual void Fill() { _b = make_shared<B>(shared_from_this()); }
};


Тема та же: сделать независимые иерархии классов, связанные между собой только через шаблонные параметры.
Эти два ссылаются друг на друга, всё ок.

Далее, где-то в main:
A1<B1<A1>> a;
a.Fill();

Всё ок.

Потом я решаю развивать A1 новым функционалом независимо и создаю A2:
template <typename B> class A2 : public A1<B>
{
};


Далее, где-то в main:
A2<B1<A2>> a;
a.Fill();

Ошибка, не могу конвертнуть A1<B1<A2>> в A2<B1<A2>>
Потому что функция описана в A1 и делает shared_ptr шаблона, в которой A2 передаётся позже, стало быть Fill об этом никак узнать не может. Переносить Fill каждый раз при создании следующего класса не хочется, да и не так всё просто, как в этом примере.

Как быть?
29 июн 17, 09:47    [20598662]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Проблема решилась тройным проходом
Т.е. вот в этой строке:
shared_ptr<M<L<S<P>>>> m = make_shared<M<L<S<P>>>>();

Для класса S, когда он в L передаётся, L ещё выглядит вот так:
template <class S> class L : public L2 <M<L<S>>, S>, public enable_shared_from_this<L<S>>

Поэтому то, что передаётся в конструктор S после того, как L проинициализировался и до того - это разные классы. Поэтому, перед тем, как создавать сам объект, я делаю фейковую иерархию, а потом её разворачиваю назад, и вот тогда всё ок.
30 июн 17, 06:43    [20601385]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Такой вопрос, есть класс(шаблон), отнаследованный от enable_shared_from_this:

class A : public enable_shared_from_this<A>
{};


есть отнаследованный класс B:

class B : public A
{}


хочется правильно сделать так:

class B : public A, public enable_shared_from_this<B>
{}
12 июл 17, 09:32    [20635655]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 34548
CEMb,

А вопрос-то в чём ? Хочется -- сделай!
12 июл 17, 10:19    [20635833]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
MasterZiv
Хочется -- сделай!
В том виде, как я написал, не компилируется.
Хочется даже так: чтобы каждый отнаследованный класс T был public enable_shared_from_this<T> неявно.
12 июл 17, 10:28    [20635879]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb,

Тут не совсем то, но почитайте )
https://stackoverflow.com/questions/15549722/double-inheritance-of-enable-shared-from-this
12 июл 17, 11:13    [20636078]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky, спасибо
Буду делать по старинке, обычный указатель, закрою все доступы и лишние конструкторы, чтобы можно было проинициализировать 1 раз и буду сидеть бояться. По идее, этот указатель (shared_from_this) передаётся дочернему объекту в конструктор, когда его создаёт этот класс. Т.е. не может быть ситуации, когда ребёнок жив, а родитель нет. Просто хотел сделать всё по-современному :)
12 июл 17, 12:28    [20636543]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb,

Главное помнить, что shared_from_this() нельзя вызывать из конструктора ))
12 июл 17, 13:57    [20636984]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky
Главное помнить, что shared_from_this() нельзя вызывать из конструктора ))
Не задумывался про это, но оно и ожидаемо, как и бросание эксепшинами в вентилятор конструкторе.
Посмотрел внутренности. Ага, WeakPtr инициализируется в конструкторе shared_ptr() после того, как выполнился конструктор класса-параметра. До этого он Empty.
Спасибо
13 июл 17, 06:08    [20639029]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Вопрос.
Есть нитка классов:
+


template <typename... TS> class StaticContainer
{};
 
template <> class StaticContainer<>
{
public:
         void EntityAdd2() {}
};

template <typename T1, typename... TS> class StaticContainer<T1, TS...> : public StaticContainer<TS...>
{
protected:
         shared_ptr<T1> m_entity;
public:

         template <typename TE> void EntityAdd2() { 
                 if (is_same<TE, T1>::value)
                          m_entity = make_shared<T1>();
                 else
                          StaticContainer<TS...>::EntityAdd2<TE>();
         }
};


в main:
StObj1 o1;
StObj2 o2;
StaticContainer<StObj1, StObj2> st12;
 
st12.EntityAdd2<StObj1>();
st12.EntityAdd2<StObj2>();

не компилируется на строчке
StaticContainer<TS...>::EntityAdd2<TE>();

C2275 на тип ТЕ. Недопустимое использование типа в качестве выражения.
Не пойму, что сделать...
Цель: если тип не совпадает, передать управление следующему в нитке классу, до тех пор, пока не найдём тип или не кончатся классы.
3 авг 17, 13:36    [20697782]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb,

Так вызывать можно только шаблонный метод:
StaticContainer<TS...>::EntityAdd2<TE>()

А StaticContainer::EntityAdd2 не шаблонный.
3 авг 17, 15:05    [20698119]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky, почему не шаблонный?

template <typename TE> void EntityAdd2() {...}
4 авг 17, 05:14    [20699423]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb,

Потому что шаблон рекурсивный и в конце рекурсии инстанцируется StaticContainer<TS...> с пустым TS т.е. StaticContainer<> у которого метод нешаблонный.
4 авг 17, 10:38    [20699866]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky, так у метода свой, отдельный шаблон на TE
4 авг 17, 11:07    [20700005]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb,

Этот не шаблонный.
template <> class StaticContainer<>
{
public:
         void EntityAdd2() {}
};
4 авг 17, 11:14    [20700027]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky, спасибо! :)
4 авг 17, 11:24    [20700077]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Не могу красиво решить проблему

Есть шаблонный класс со значением внутри:

T value_;


Хочу написать функцию, которая принимает значение для (любого типа) value_ в виде строки.

C::SetStrValue(string& strValue)
{
	istringstream strm;
	strm.str(strValue);
	strm >> value_;
}


всё ок, пока не попадается строка с пробелами. std::noskipws не спасает. С ним просто останавливается обработка строки на пробеле, без него из строки пробелы пропадают. Как быть?
17 янв 18, 10:07    [21112906]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
CEMb,

Сначала надо сформулировать как читать строку - например до ближайшего \n, или до конца потока.
Потом надо создать специализацию для строк, и там применить нужный алгоритм чтения строки.
Для построчного чтения или до произвольного разделителя - std::getline
17 янв 18, 12:10    [21113355]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Anatoly Moskovsky
т.е. делать свой парсер строки? Ну вот не хотелось этого делать. Строковый поток отлично справляется с этими задачи, кроме одного момента про, собственно, саму строку.
Сейчас пробую сделать через SFINAE.
18 янв 18, 05:24    [21115255]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
такой вопрос:

есть иерархия классов, для простоты:

class A
{
	type_A a_;
public:
	const type_A& Get() const { return a_; }
};

class B : public A
{
	type_B b_;
public:
	const type_B& Get() const { return b_; }
};

class C : public B
{
	type_C c_;
public:
	const type_C& Get() const { return c_; }
};


на самом деле это один класс-шаблон, я расписал в иерархию, чтобы было нагляднее
вопрос: есть ли способ написать метод Get, чтобы оно работало, как написано выше? Чтобы возвращал значение то, которое запрашивается? Именно через возвращаемое значение. Имя должно метода должно быть одинаковое (потому что это один класс).
Через шаблонный метод у меня не получилось, потому что при несовпадении типа метода-шаблона(TE) и класса шаблона(T1) компилятор ругается на несовместимость возвращаемого значения, хотя реально его никогда возвращать не будет:

template <typename TE> auto Class<T1, TS...>::Get(tstring& name) -> shared_ptr<TE>
{
	if (is_same<TE, T1>::value)
		return value_; // here
	else
		return Class<TS...>::Get<TE>(name);
}
25 янв 18, 12:51    [21137941]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
CEMb,
typedef const char type_A;
typedef const short type_B;
typedef const int type_C;

class C 
{
public:

  struct __Get;

private:

  type_A a_ = 0x0a;
  type_B b_ = 0x0b;
  type_C c_ = 0x0c;
  
  friend struct __Get;

public:

  struct __Get
  {
  private:

    operator const C& () const
    {
      register size_t offset = reinterpret_cast<size_t>(&((C*)0)->Get);
      return *reinterpret_cast<const C*>((size_t)this - offset);
    }

  public:

    operator type_A& () const
    {
      return ((const C&)*this).a_;
    }
    
    operator type_B& () const
    {
      return ((const C&)*this).b_;
    }

    operator type_C& () const
    {
      return ((const C&)*this).c_;
    }
    
  }
  Get;
};

#pragma argsused
int __cdecl main(int argc, char* argv[])
{
  C c;
  type_A& i = c.Get;
  type_B& j = c.Get;
  type_C& k = c.Get;
  .
  .
  .
  return 0;
}
25 янв 18, 15:37    [21138815]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
rdb_dev, интересная идея, спасибо. Я так понял, что даже без структуры Get, просто с кастами оно тоже работать будет?
Но вот typedef у меня не получится применить, так как набор типов в объекте заранее неизвестен, это шаблон, на каждом объекте набор типов определяется параметрами шаблона. Но вот с кастами надо попробовать, спасибо.
26 янв 18, 05:46    [21140177]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Guest
((C*)0)->Get

UB
9 мар 18, 18:41    [21246273]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
можно как-то в качестве параметра шаблона использовать формулу?

что-то типа
temlate<typename F> int Do (int a, int b)
{
return F(a, b);
}


А без лябмд?
31 мар 18, 11:42    [21301666]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
CEMb
можно как-то в качестве параметра шаблона использовать формулу?

Можно использовать класс, в котором использовать (статическую) функцию с нужной сигнатурой.
Но вот если у меня F очень плотно используется? Буквально, хочу в одном месте a+b, а в другом a-2*b, например. И таких штук 10-20, не хочется под всё классы городить, и дорого это по производительности.

Ну а с лямбдами-то это можно сделать?
31 мар 18, 11:45    [21301671]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
CEMb
Буквально, хочу в одном месте a+b, а в другом a-2*b, например.
инлайнами и опциями компилятора у меня таки это получилось
31 мар 18, 21:58    [21302221]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
White Owl
Member

Откуда:
Сообщений: 12419
CEMb
CEMb
можно как-то в качестве параметра шаблона использовать формулу?

Можно использовать класс, в котором использовать (статическую) функцию с нужной сигнатурой.
Но вот если у меня F очень плотно используется? Буквально, хочу в одном месте a+b, а в другом a-2*b, например. И таких штук 10-20, не хочется под всё классы городить, и дорого это по производительности.

Ну а с лямбдами-то это можно сделать?


template <typename T, typename L>
T do_lambda(T a, T b, L func) {
    return func(a, b);
}

do_lamda(1, 2, [](int a, int b){return (a+b);});
2 апр 18, 18:58    [21306377]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
White Owl
да, отлично, даже без inline код встраивается без вызова! Жаль только что у меня проект в 2010, там лямбд нету.

Отдельно порадовал оптимизатор, к примеру do_lamda(rand(), 1, ...) сводится в результате к инкременту. Ну и вообще без rand и проверки возвращаемого значения не удалось собрать, так как оптимизатор не видел смысла в этом коде, просто выкидывал его из релиза
3 апр 18, 06:05    [21306783]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
((C*)0)->Get
UB
И что же тут неопределённого для LE?
3 апр 18, 11:19    [21307511]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
a guest
((C*)0)->Get
UB
И что же тут неопределённого для LE?
Что такое "LE"? Little Endian?
3 апр 18, 11:26    [21307541]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest, да.
3 апр 18, 11:58    [21307730]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev, не понимаю, при чём тут вообще endianness.
null pointer не указывает ни на какой объект, поэтому возможность получать доступ к data member-у сомнительна.
3 апр 18, 12:11    [21307772]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
rdb_dev, не понимаю, при чём тут вообще endianness.
null pointer не указывает ни на какой объект, поэтому возможность получать доступ к data member-у сомнительна.
А где ты видишь доступ к члену экземпляра класса по нулевому указателю?
operator const C& () const
{
  register size_t offset = reinterpret_cast<size_t>(&((C*)0)->Get);
  return *reinterpret_cast<const C*>((size_t)this - offset);
}
Это банальный расчёт смещения члена внутри структуры экземпляра класса, чтобы инкапсулированный объект мог получить указатель на инкапсулирующий.
3 апр 18, 13:10    [21308019]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
a guest
rdb_dev, не понимаю, при чём тут вообще endianness.
null pointer не указывает ни на какой объект, поэтому возможность получать доступ к data member-у сомнительна.
А где ты видишь доступ к члену экземпляра класса по нулевому указателю?
Здесь:
((C*)0)->Get

rdb_dev
operator const C& () const
{
  register size_t offset = reinterpret_cast<size_t>(&((C*)0)->Get);
  return *reinterpret_cast<const C*>((size_t)this - offset);
}
Это банальный расчёт смещения члена внутри структуры экземпляра класса, чтобы инкапсулированный объект мог получить указатель на инкапсулирующий.
Который всего лишь приводит к
https://wandbox.org/permlink/uf0utxeaF4023z0u
prog.cc:29:58: runtime error: member access within null pointer of type 'C'
:D
3 апр 18, 13:15    [21308043]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
rdb_dev
пропущено...
А где ты видишь доступ к члену экземпляра класса по нулевому указателю?
Здесь: [src c++]
((C*)0)->Get
Еще раз повторяю - в моём нет доступа к члену объекта по нулевому указателю - нет ни чтения структуры, ни вызова функции. Учите C++ ABI !
3 апр 18, 13:25    [21308085]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
a guest
пропущено...
Здесь: [src c++]
((C*)0)->Get
Еще раз повторяю - в моём нет доступа к члену объекта по нулевому указателю - нет ни чтения структуры, ни вызова функции. Учите C++ ABI !
prog.cc:29:58: runtime error: member access within null pointer of type 'C'
3 апр 18, 13:28    [21308106]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
((const C&)*this).a_;

UB
((const C&)*this).b_;

UB
((const C&)*this).c_;

UB
3 апр 18, 13:35    [21308147]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest, еще и с перегрузкой операторов приведения типа не знаком?
Собрать на g++ и пройтись отладчиком - не судьба?
3 апр 18, 13:53    [21308212]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev, ой-ой. Извените. Оператор приведения типа же определён.

Который весь сплошь из УГ UB состоит. Даже если заменить
reinterpret_cast<size_t>(&((C*)0)->Get)
на offsetof (который до C++17 для данного класса был UB, а теперь "conditionally supported") и он будет supported в данной реализации, то арифметика "указателей" там — останется UB.
3 апр 18, 13:59    [21308241]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
Собрать на g++ и пройтись отладчиком - не судьба?
Принести сюда цитат из стандарта, которые покажут, что код ­валиден — не судьба?
3 апр 18, 14:00    [21308243]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest, еще раз - где здесь доступ к члену экземпляра класса (чтение свойства/вызов метода) по нулевому указателю экземпляра?
operator const C& () const
{
  register size_t offset = reinterpret_cast<size_t>(&((C*)0)->Get);
  return *reinterpret_cast<const C*>((size_t)this - offset);
}

"&((C*)0)->Get" - это что? Амперсанд (взятие адреса) видим?
3 апр 18, 14:03    [21308263]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
rdb_dev
Собрать на g++ и пройтись отладчиком - не судьба?
Принести сюда цитат из стандарта, которые покажут, что код ­валиден — не судьба?
Этот код валиден даже для структур чистого Си. Открывай раздел ABI стандарта и читай!
3 апр 18, 14:05    [21308277]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
Открывай раздел ABI стандарта и читай!
Что-то не найду в http://eel.is/c draft/ раздел "ABI".
3 апр 18, 14:48    [21308560]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
rdb_dev
"&((C*)0)->Get" - это что? Амперсанд (взятие адреса) видим?
где здесь доступ к члену экземпляра класса (чтение свойства/вызов метода) по нулевому указателю экземпляра?

Согласно стандарту, E1->E2 эквивалентно (*(E1)).E2
Таким образом "->" это в том числе и разыменование указателя.

В стандарте (всех версий), разыменование нулевого указателя упоминается как пример UB. (С++17 8.3.2.5)

Но в стандарте есть места противоречащие этому.
Вот тут дискуссия на эту тему (она ссылается на старый стандарт, но в последнем все осталось так же)
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232

Но учитывая что как минимум одна из трактовок стандарта считает это UB и то что многие компиляторы агрессивно оптимизируют код, удаляя целые блоки кода имеющие UB, то я бы не стал такое применять в продакшене.
Тем более что в VS2010 про который тут говорилось есть встроенный offsetof.
3 апр 18, 14:50    [21308575]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
Anatoly Moskovsky
В стандарте (всех версий), разыменование нулевого указателя упоминается как пример UB. (С++17 8.3.2.5).
В какой версии драфта пункт 8.3.2.5?
3 апр 18, 14:53    [21308600]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky, а где написано, что нельзя разыменовывать указатель с адресом 0x0 (не путать с указателем NULL, который хоть и представлен во многих компиляторах именно как (void*)0)?
3 апр 18, 15:12    [21308697]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
где написано, что нельзя
В C++ так вопрос не ставится. В C++ спрашивается "где определено поведение такой-то конструкции?". А если оно не определено — то получается неопределённое поведение.

rdb_dev
указатель с адресом 0x0
Можно узнать способ получения указателя с адресом 0x0?
3 апр 18, 15:20    [21308747]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
struct __Get;

http://eel.is/c draft/lex.name#3
In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
— Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
3 апр 18, 15:25    [21308775]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
rdb_dev
указатель с адресом 0x0
Можно узнать способ получения указателя с адресом 0x0?
Можно! Открой заголовочные файлы гнуса и узри в них:
#if defined(__GNUG__) && __GNUG__ >= 3
#define NULL __null
#else   /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else   /* C++ */
#ifndef _WIN64
#define NULL 0
#else
#define NULL 0LL
#endif  /* W64 */


Но лично я предпочитаю что-то типа:
    struct is
    {
    .
    .
    .
    public:

      template <class T>
      __INLINE
      static bool __fastcall Nil(register T* const ptr)
      {
#     if defined(__WIN32__) || defined(__WIN64__)
        return (0x00010000 > (size_t)ptr);
#     else
        return (0x0 == (size_t)ptr);
#     endif
      }
    .
    .
    .
    };
3 апр 18, 15:27    [21308783]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
rdb_dev
struct __Get;

http://eel.is/c draft/lex.name#3
In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
— Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
Большинству разработчиков на это совершенно пофигу! Ты найдешь пренебрежение этой рекомендацией даже в исходниках RHEL, не говоря уже о заголовочных файлах реализации cstdlib.
__mingw_ovr
__attribute__((__format__ (gnu_printf, 1, 2))) __MINGW_ATTRIB_NONNULL(1)
int printf (const char *__format, ...)
{
  register int __retval;
  __builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
  __retval = __mingw_vfprintf( stdout, __format, __local_argv );
  __builtin_va_end( __local_argv );
  return __retval;
}
3 апр 18, 15:31    [21308803]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
a guest
пропущено...
Можно узнать способ получения указателя с адресом 0x0?
Можно! Открой заголовочные файлы гнуса и узри в них:
#if defined(__GNUG__) && __GNUG__ >= 3
#define NULL __null
#else   /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else   /* C++ */
#ifndef _WIN64
#define NULL 0
#else
#define NULL 0LL
#endif  /* W64 */
Ну и в какой конкретно строчке получается указатель с адресом 0x0, но при этом не нулевой указатель?

rdb_dev
Но лично я предпочитаю что-то типа:
    struct is
    {
    .
    .
    .
    public:

      template <class T>
      __INLINE
      static bool __fastcall Nil(register T* const ptr)
      {
#     if defined(__WIN32__) || defined(__WIN64__)
        return (0x00010000 > (size_t)ptr);
#     else
        return (0x0 == (size_t)ptr);
#     endif
      }
    .
    .
    .
    };
А тут?
3 апр 18, 15:34    [21308819]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
Ты найдешь пренебрежение этой рекомендацией даже в исходниках RHEL, не говоря уже о заголовочных файлах реализации cstdlib.

1. Стандарт резервирует идентификаторы определённого вида для реализации.
2. Реализация (в данном случае — cstdlib) использует идентификаторы данного вида.

Как ты в следовании этой рекомендации смог увидеть пренебрежение ею?
3 апр 18, 15:37    [21308832]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
Ну и в какой конкретно строчке получается указатель с адресом 0x0, но при этом не нулевой указатель?
Поясняю для непонятливых - адреса с 0x0 по 0x0000FFFF в ОС Windows для x86 являются инвалидными только благодаря самой реализации ОС, в которой при доступе по этим адресам возникает исключение page fault, но это не значит, что эти адреса инвалидны в реализациях любых ОС, в т.ч. проприетарных или в реализациях прошивок контроллеров, которые могут хранить по этим адресам некие заранее известные структуры данных по заранее известным смещениям. Поэтому, валидно любое приведение любых адресов в арифметике указателей, чтобы там не насочиняли стандартописатели.
3 апр 18, 15:49    [21308888]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
валидно любое приведение любых адресов в арифметике указателей
Можно цитаты из стандарта?
3 апр 18, 15:53    [21308906]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
rdb_dev
валидно любое приведение любых адресов в арифметике указателей
Можно цитаты из стандарта?
Цитаты из стандарта о том, что для процессоров и контроллеров валидны все доступные им адреса памяти?
3 апр 18, 15:59    [21308965]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
rdb_dev
Anatoly Moskovsky, а где написано, что нельзя разыменовывать указатель с адресом 0x0 (не путать с указателем NULL, который хоть и представлен во многих компиляторах именно как (void*)0)?

4.10 параграф 1
A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t. A
null pointer constant can be converted to a pointer type; the result is the null pointer value of that type


Т.е. число 0 при преобразовании в указатель дает нулевой указатель (независимо от того как на данной платформе реализован нулевой указатель).
Таким образом (T*)0 - это нулевой указатель.

a guest
В какой версии драфта пункт 8.3.2.5?

n4594, 8.3.2 параграф 5
3 апр 18, 16:01    [21308975]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
rdb_dev
Цитаты из стандарта о том, что для процессоров и контроллеров валидны все доступные им адреса памяти?

То что адрес 0 это такой же адрес для процессора как и другие не противоречит тому что в С++ обращение по этому адресу - UB.
Из С++ обращаться к нему нельзя, а из ассемблера например можно.
3 апр 18, 16:04    [21308998]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
Anatoly Moskovsky
a guest
В какой версии драфта пункт 8.3.2.5?

n4594, 8.3.2 параграф 5
Хм. Но ведь это не
Anatoly Moskovsky
разыменование нулевого указателя упоминается как пример UB.
Там написано что UB это инициализация ссылки выражением `*p` если `p == nullptr` (ну или вообще инициализация не валидным указателем на объект).
3 апр 18, 16:06    [21309011]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky
rdb_dev
Anatoly Moskovsky, а где написано, что нельзя разыменовывать указатель с адресом 0x0 (не путать с указателем NULL, который хоть и представлен во многих компиляторах именно как (void*)0)?

4.10 параграф 1
A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t. A
null pointer constant can be converted to a pointer type; the result is the null pointer value of that type


Т.е. число 0 при преобразовании в указатель дает нулевой указатель (независимо от того как на данной платформе реализован нулевой указатель).
Таким образом (T*)0 - это нулевой указатель.
Нет! В стандарте не сказано, что null указатель, это тоже самое, что (void*)0, хотя в некоторых компиляторах это действительно так! На эту тему было сломано немало копий именно по той простой причине, что для процессоров и контроллеров, это абсолютно реальный адрес оперативной памяти, по которому может находиться информация. Именно по этой причине в стандарт введен null указатель, который совсем не (void*)0, а именно неинициализированный указатель.
3 апр 18, 16:06    [21309020]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
a guest
инициализация не валидным указателем на объект
инициализация выражением, которое не обозначает валидный объект.
3 апр 18, 16:07    [21309025]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
rdb_dev
Можно! Открой заголовочные файлы гнуса и узри в них

Внутри кода стандартной библиотеки могут быть какие угодно хаки, не всегда даже являющиеся С++.
Так что не стоит оттуда брать примеры ))
3 апр 18, 16:14    [21309056]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
a guest
инициализация не валидным указателем на объект
инициализация выражением, которое не обозначает валидный объект.
А какая разница? Представь, что ты пишешь на Си часть прошивки к контроллеру, а до тебя разработчики, что писали, к примеру boot loader на ассемблере, поместили в начальные адреса адресного пространства некие статичные инициализированные в бутстрапе структуры данных. Зная о формате этих структур, ты как к ним будешь доступ получать?
3 апр 18, 16:15    [21309057]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky
Внутри кода стандартной библиотеки могут быть какие угодно хаки, не всегда даже являющиеся С++.
Так что не стоит оттуда брать примеры ))
Без "грязных хаков" на Си/С++ системные вещи вообще не пишутся! Есть идеалисты, придумывающие стандарт, которому рекомендовано следовать, а есть программисты, которые вынуждены обходить ограничения стандартов.
3 апр 18, 16:18    [21309064]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
rdb_dev
Нет! В стандарте не сказано, что null указатель, это тоже самое, что (void*)0

Нет конечно, там сказано что (void*)0 дает null указатель. То, с чем вы пытаетесь спорить.
rdb_dev
Именно по этой причине в стандарт введен null указатель, который совсем не (void*)0, а именно неинициализированный указатель.

Ггггг.
Нет. Основная причина это корректные перегрузки функций.
Со старым NULL:
void f(char*);
void f(int);
f(NULL); // ошибка: не понятно что вызывать (обе функции могут быть вызваны), хотя в большинстве случаев имеется в виду вызов f(char*)

С nullptr:
void f(char*);
void f(int);
f(nullptr); // вызывается f(char*), как и задумывалось
3 апр 18, 16:24    [21309095]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky,

"2.14.7 Pointer literals [lex.nullptr]
pointer-literal:
nullptr
The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t. [ Note: std::nullptr_t
is a distinct type that is neither a pointer type nor a pointer to member type; rather, a prvalue of this type is
a null pointer constant and can be converted to a null pointer value or null member pointer value. See 4.10
and 4.11. —end note ]"

Смотрим 4.10 и 4.11:

"4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero
or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result
is the null pointer value of that type and is distinguishable from every other value of pointer to object or
pointer to function type
. Such a conversion is called a null pointer conversion. Two null pointer values of the
same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is
a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4).
A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The
resulting prvalue is not a null pointer value. —end note ]"

"4.11 Pointer to member conversions [conv.mem]
1 A null pointer constant (4.10) can be converted to a pointer to member type; the result is the null member
pointer value of that type and is distinguishable from any pointer to member not created from a null pointer
constant
. Such a conversion is called a null member pointer conversion. Two null member pointer values
of the same type shall compare equal. The conversion of a null pointer constant to a pointer to member of
cv-qualified type is a single conversion, and not the sequence of a pointer to member conversion followed by
a qualification conversion (4.4)."

Никак не могу разглядеть - в каком месте тут UB?
3 апр 18, 16:50    [21309194]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky
[/src]
С nullptr:
void f(char*);
void f(int);
f(nullptr); // вызывается f(char*), как и задумывалось
Еще не могу понять, каким образом компилятор C++ должен "дедуктировать", что тип std::nullptr_t, подходит для вызова функции void f(char*)?
3 апр 18, 16:53    [21309202]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a guest
Member

Откуда:
Сообщений: 155
rdb_dev
Никак не могу разглядеть - в каком месте тут UB?
Да никто и не говорил, что UB из-за каста нуля к указателю.
Ты, похоже, вообще не понимаешь, что тебе пишут.
3 апр 18, 17:35    [21309343]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
rdb_dev
Никак не могу разглядеть

rdb_dev
Еще не могу понять

Похоже нет смысла продолжать. ))
3 апр 18, 17:59    [21309417]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
a guest
rdb_dev
Никак не могу разглядеть - в каком месте тут UB?
Да никто и не говорил, что UB из-за каста нуля к указателю.
Ты, похоже, вообще не понимаешь, что тебе пишут.
Алилуия!
Я надеюсь, п.1 параграфа 4.11 стандарта достаточно доходчиво объясняет что, к чему и как может быть приведено?
4 апр 18, 01:50    [21310191]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky
Похоже нет смысла продолжать. ))
Ну еще бы!...
Напомни еще разок, что так к чему приводить - UB? :)
4 апр 18, 02:03    [21310196]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky
rdb_dev
Еще не могу понять

Похоже нет смысла продолжать. ))
На счёт "deduction" nullptr для выбора void f(char*) соглашусь - вчера затупил... :) Но на счет якобы UB при конвертации (size_t)0 к типизированному указателю на экземпляр структуры/класса/члена совершенно не согласен.
4 апр 18, 09:33    [21310455]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6397
rdb_dev
Но на счет якобы UB при конвертации (size_t)0 к типизированному указателю на экземпляр структуры/класса/члена совершенно не согласен.

UB не тут. Но смысла дальше объяснять нет, т.к. уже не раз пытались. Кто захотел - понял, а кто не понял тот поймет )))
4 апр 18, 11:34    [21311015]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
Anatoly Moskovsky, подытожим? :)
Anatoly Moskovsky
rdb_dev
"&((C*)0)->Get" - это что? Амперсанд (взятие адреса) видим?
где здесь доступ к члену экземпляра класса (чтение свойства/вызов метода) по нулевому указателю экземпляра?

Согласно стандарту, E1->E2 эквивалентно (*(E1)).E2
Таким образом "->" это в том числе и разыменование указателя.

В стандарте (всех версий), разыменование нулевого указателя упоминается как пример UB. (С++17 8.3.2.5)
По очевидным причинам, в личном пользовании у меня нет стандарта C++17, поэтому я пользую draft N4659. Привожу абзац полностью:
"8.2.5 Class member access [expr.ref]
1 A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template (17.2),
and then followed by an id-expression, is a postfix expression. The postfix expression before the dot or arrow
is evaluated;67 the result of that evaluation, together with the id-expression, determines the result of the
entire postfix expression.

2 For the first option (dot) the first expression shall be a glvalue having complete class type. For the second
option (arrow) the first expression shall be a prvalue having pointer to complete class type. The expression
E1->E2 is converted to the equivalent form (*(E1)).E2; the remainder of 8.2.5 will address only the first
option (dot).68 In either case, the id-expression shall name a member of the class or of one of its base classes.
[ Note: Because the name of a class is inserted in its class scope (Clause 12), the name of a class is also
considered a nested member of that class. —end note ] [ Note: 6.4.5 describes how names are looked up
after the . and -> operators. —end note ]
-------------------------------------
67) If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to
determine the value of the entire postfix expression, for example if the id-expression denotes a static member.
68) Note that (*(E1)) is an lvalue.
"

Никакого доступа к члену класса в данном контексте нет, так как и E1->E2, и (*(E1)).E2, это, всего лишь, место в памяти. Конечно, если упомянутые выражения я использую в неизменном виде как rvalue или lvalue, при том, что в E1 будет nullptr, то получу UB, а на винде даже page fault, но при "evaluation" выражения с оператором взятия адреса (&), rvalue уже не будет являться доступом к экземпляру класса и/или члену экземпляра. Стандарт же не идиоты писали!
4 апр 18, 13:46    [21311704]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Я надеваю свой шаблонный плащ и шаблонную шляпу...

Слушайте, можно как-нибудь сделать перечисление/цикл по типам?

К примеру, схематично, надо так:

template <typename T> class C
{
public:
	void Do(void){};
}
vector<typename> types;
types.emplace_back(int);
types.emplace_back(wstring);
types.emplace_back(float);

// somewhere else
for (vector<typename>::const_iterator it = types.cbegin(); it < types.cend(); it++)
{
	C<*it>c;
	c.Do();
}


Это можно сделать с рекурсивными шаблонами, но громоздко получается.

У меня есть некоторые структуры типов данных, которые завязаны на типы, т.е. дублируются по ним (int, float, ...) и почти функционалом не отличаются (atoi, atof, etc.). Но отдельных функций работы с ними много и они большие(циклы, перевызовы других функций, логика разбора), поэтому рекурсивное определение шаблонов тут вообще неудобно делать. Вот и думаю, как бы это сделать. У Александреску вроде было что-то такое в Локи, но не уверен, что оно сильно от рекурсивного объявления отличается.
29 сен 18, 10:38    [21689763]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
NekZ
Member

Откуда: Stuttgart, Baden-Württemberg.
Сообщений: 3568
CEMb,

Тебе нужны boost::mpl::vector и boost::mpl::for_each.
29 сен 18, 10:54    [21689764]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
NekZ, о, спасибо, не знал, что такое есть. В сопутствующей доке этого не нашёл (в интернете есть).

У меня там основная проблема была в выносе кода в отдельные функции. Всё-таки не поленился и вынес...
2 окт 18, 05:09    [21692103]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
NekZ
Member

Откуда: Stuttgart, Baden-Württemberg.
Сообщений: 3568
CEMb,

Советую к прочтению Advanced Metaprogramming in Classic C++ by Davide Di Gennaro. Там такие финты ушами описаны, после которых и жить не хочется,
когда ты знаешь что где-то это может применяться. У тебя сразу все вопросы отпадут касательно реализации Boost MPL.
2 окт 18, 07:15    [21692121]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
NekZ
Там такие финты ушами описаны, после которых и жить не хочется,
когда ты знаешь что где-то это может применяться. У тебя сразу все вопросы отпадут касательно реализации Boost MPL.

Хм, это интересно :)
Мне где-то попадались финты: люди сделали тетрис в потоке отладки сборки проекта
3 окт 18, 05:39    [21693602]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
CEMb
NekZ, о, спасибо, не знал, что такое есть. В сопутствующей доке этого не нашёл (в интернете есть).

У меня там основная проблема была в выносе кода в отдельные функции. Всё-таки не поленился и вынес...
Если мне не изменяет память, for_each вкрячили в стандарт C++14. В GCC он точно есть.
3 окт 18, 09:25    [21693684]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
NekZ
Member

Откуда: Stuttgart, Baden-Württemberg.
Сообщений: 3568
rdb_dev
Если мне не изменяет память, for_each вкрячили в стандарт C++14. В GCC он точно есть.

for_each по вектору из типов?
3 окт 18, 09:27    [21693686]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3062
NekZ,
+ Цитата из stl_algo.h (#include <algorithm>)
  /**
   *  @brief Apply a function to every element of a sequence.
   *  @ingroup non_mutating_algorithms
   *  @param  __first  An input iterator.
   *  @param  __last   An input iterator.
   *  @param  __f      A unary function object.
   *  @return   @p __f
   *
   *  Applies the function object @p __f to each element in the range
   *  @p [first,last).  @p __f must not modify the order of the sequence.
   *  If @p __f has a return value it is ignored.
  */
  template<typename _InputIterator, typename _Function>
    _Function
    for_each(_InputIterator __first, _InputIterator __last, _Function __f)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      for (; __first != __last; ++__first)
	__f(*__first);
      return __f; // N.B. [alg.foreach] says std::move(f) but it's redundant.
    }
3 окт 18, 10:06    [21693724]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
NekZ
Member

Откуда: Stuttgart, Baden-Württemberg.
Сообщений: 3568
rdb_dev
NekZ,
+ Цитата из stl_algo.h (#include <algorithm>)
  /**
   *  @brief Apply a function to every element of a sequence.
   *  @ingroup non_mutating_algorithms
   *  @param  __first  An input iterator.
   *  @param  __last   An input iterator.
   *  @param  __f      A unary function object.
   *  @return   @p __f
   *
   *  Applies the function object @p __f to each element in the range
   *  @p [first,last).  @p __f must not modify the order of the sequence.
   *  If @p __f has a return value it is ignored.
  */
  template<typename _InputIterator, typename _Function>
    _Function
    for_each(_InputIterator __first, _InputIterator __last, _Function __f)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      for (; __first != __last; ++__first)
	__f(*__first);
      return __f; // N.B. [alg.foreach] says std::move(f) but it's redundant.
    }

Проблема только в том, что это не имеет никакого отношения к теме и существует с допотопных времён.
Здесь-то нужен цикл по вектору типов в compile-time, в то время как обычный std::for_each выполняется в рантайме и не по типам совсем.

boost::mpl::for_each является шаблонным типом, а не функцией.
3 окт 18, 10:49    [21693776]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
У меня вопрос про специализацию метода шаблона.

Если делаю так, в заголовке:

emplate<typename T> class C
{
public:
	C<T>(){} // body in
};

// string impl
template<> C::C<string>()
{}


Всё ок. Но не хочу городить код в описании класса, так как конструктор большой, поэтому хочу вынести описание общего конструктора за скобки:

emplate<typename T> class C
{
public:
	C<T>();
};

template<typename T>C::C<T>() // body out
{}

// string impl
template<> C::C<string>()
{}

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

если вынести специализацю в cpp(вроде это же явный код, там ему и место) - тоже ошибка линкера, но другая, но смысл тот же, функция уже определена
спасает только внос основного конструктора в описание класса-шаблона.
чую, какой-то абсолютно тупой косяк, но понять не могу Картинка с другого сайта.
и почему оно собирается, когда специализация находится в заголовочном файле?
18 ноя 18, 11:56    [21737340]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
template<typename T>C<T>::C() // body out, fixed
{}
И это MS VC++17
18 ноя 18, 12:04    [21737345]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
CEMb
если вынести специализацю в cpp
то код для не неё не собирается. Странно.
18 ноя 18, 12:15    [21737352]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7896
CEMb
если вынести специализацю в cpp(вроде это же явный код, там ему и место)

если хочешь, чтобы конструктор для специализации был в cpp попробуй вынести в cpp
template class C<string>;
18 ноя 18, 13:51    [21737399]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
NekZ
Member

Откуда: Stuttgart, Baden-Württemberg.
Сообщений: 3568
CEMb,

Ни разу не видел чтобы так кто-то писал. Даже сложно понять чего ты этим хотел добиться
template<typename T> class C
{
public:
	C<T>();
};


Это тоже какая-то лажа, у тебя же не template-конструктор, а класс:
// string impl
template<> C::C<string>()
{}


Почему не так?
// string impl
template<> C<string>::C()
{}


В общем таким должен быть хедер:
template<typename T> class C
{
public:
	C();
};


А таким cpp-шник:
template<> C<string>::C()
{
}


А заодно, раз уж ты ограничиваешь инстанциации шаблона, то сделай это на уровне компилятора, а не линкера,
либо через SFINAE, либо явным путём всех возможных специализаций всего класса в хедере.
18 ноя 18, 14:24    [21737410]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
NekZ
Почему не так?
Оно так и есть, просто я торопился :)
NekZ
В общем таким должен быть хедер:
ну вот оно так не собирается, про это и был воспрос.

NekZ
А заодно, раз уж ты ограничиваешь инстанциации шаблона, то сделай это на уровне компилятора, а не линкера,
либо через SFINAE, либо явным путём всех возможных специализаций всего класса в хедере.
Мне нужно просто переопределить один метод для одного типа(в качестве параметра шаблона). SFINAE, конечно, можно приделать, но это слишком для такой простой ситуации. Мне надо вот, как тут, но код общей функции print вынести из описания класса.
18 ноя 18, 16:34    [21737464]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
NekZ
А таким cpp-шник:
А, да, если код в cpp - он не собирается, т.е. компилятор его игнорирует.
18 ноя 18, 16:43    [21737466]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
NekZ
Member

Откуда: Stuttgart, Baden-Württemberg.
Сообщений: 3568
CEMb
NekZ
А таким cpp-шник:
А, да, если код в cpp - он не собирается, т.е. компилятор его игнорирует.

Друг, ну что за формулировки? Наверное, ты имел в виду линкер?
Кстати, можно было бы попробовать трюк с extern template.
19 ноя 18, 07:54    [21737748]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
NekZ
Друг, ну что за формулировки? Наверное, ты имел в виду линкер?
Нет, именно компилятор. Конечного(скомпилированного) кода нет. Если я ставлю в cpp-коде брекпоинт, среда его убирает с формулировкой, что по этому cpp-коду не было ничего собрано. Тогда как брекпоинт в заголовке ставится и отрабатывает - код есть.
NekZ
Кстати, можно было бы попробовать трюк с extern template.
Нет, надо разобраться в вопросе :) Там должно быть всё просто. Я сейчас возьму таймаут(много работы) и чуть позже спокойно посмотрю, почему оно так и как оно должно быть. А пока сделаю, чтоб просто работало :}
20 ноя 18, 05:34    [21738678]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
+
CEMb
Я сейчас возьму таймаут(много работы) и чуть позже спокойно посмотрю
ты сам в это веришь?
У меня вопрос:
class A1
{
public:
	void fn(const char* s) {}
};
class B1 : public A1
{
public:
	using A1::fn;
public:
	void fn(float f) {}
};
// in far-far gxy:
	B1 b1;
	b1.fn("a?");
вопрос: почему оно не работает без using A1:fn?

При чём тут шаблоны? Когда я пишу класс-шаблон с переменным числом шаблонных параметров, у меня в нём есть одинаковый метод-шаблон, который хочется видеть из всех итераций класса. Но как для него написать using?
20 май 19, 06:21    [21888490]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
код для большего понимания ситуации:

// base
template <typename... TS> class Params
{};
// empty
template <> class Params<>
{};
// first
template <typename T1> class Params<T1> : public Params<>
{
public:
	template <typename TE> auto ParamGet(const wstring& name, const TE&) -> enable_if_t<is_same<TE, T1>::value , TE>
	{
		return 0;
	}
};
// iteration
template <typename T1, typename... TS> class Params<T1, TS...> : public Params<TS...>
{
public:
	using Params<TS...>::ParamGet; // и тогда мы видим эти методы в коде, но только не шаблонные, типа:
	//auto ParamGet(const wstring& name, const T1&) -> typename T1
	//{
	//	return 0;
	//}
	template <typename TE> auto ParamGet(const wstring& name, const TE&) -> enable_if_t<is_same<TE, T1>::value, TE>
	{
		return 0;
	}
};


// in fr-fr gx
	Params<int, float, wstring> params;
	// work
	wstring str = params.Params<wstring>::ParamGet<wstring>(L"str", L"");
	// wrong, cause c++ standard 13.2
	wstring str2 = params./*Params<wstring>::*/ParamGet<wstring>(L"str", L"");


Вот если ParamGet не шаблон, то using Params<TS...>::ParamGet; добавляет видимости методам из классов-предков, и всё становится ок. Как написать правильный uning, чтобы это работало с шаблонами.

PS: можно написать !is_same<TE, T1> и прокидывать методы из предков, но тогда возникают неприятные предупреждения компилятора о множественных реализациях.

PPS: если до вечера не найду решение, то буду использовать передачу параметра в функцию и неявную специализацию. И страдать от того, что всё в две строчки, а могло быть в одну.
20 май 19, 09:25    [21888556]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Проблема решилась переносом using-ов в хвост класса. Видимо, как-то так работает построитель классов, видимость устанавливается после того, как развернут метод, а не до того. Ну, т.е. можно и до того, но это должен быть готовый метод в классе-предке. А тут его ещё не было.
20 май 19, 12:50    [21888769]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7896
CEMb,

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

и еще

вместо return 0 лучше использовать return {}, поскольку возвращаемое значение не обязательно будет интегральным типом, но также и классом
20 май 19, 12:56    [21888781]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Cerebrum, нет, я хочу хранить множества параметров разных типов в одной коробке.
Сейчас я указываю типы параметров, которые лежат в коробке: <int, float, string> - в качестве параметров шаблона.
- множество типов заранее известно
- количество элементов заранее не известно
- всё на момент компиляции
обычно это классическая задача с одним классом-предком и кучей наследников, тип определяется динамически, в контейнере хранятся указатели на объекты класса-предка. Но я хочу сделать типизацию на момент компиляции, так как мы там знаем, какие типы мы складываем в коробку, почему бы это не использовать сразу?

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

ну и хочется сделать так:
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 {}
это просто заглушка для демонстрации была, там возвращается или параметр-обёртка или значение параметра.
20 май 19, 20:23    [21889200]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Неужели никому не надо? Картинка с другого сайта.

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

Объект в частном случае вышел такой:
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_); }
};

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

		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 должен "быть" только в "последнем" классе:

	auto AnyGet(const string& name) -> AnyPass<ParamsAny, TS...>
	{
		return AnyPass<ParamsAny, TS...>(name, this);
	}

(хотя он есть везде, просто невидим)
если кто знает, как это можно сделать одним методом, подскажите :)
21 май 19, 13:51    [21889714]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
добрый день
где в стандарте почитать про создание и порядок выполнения преобразований, когда используются шаблоны?

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

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

я получу ошибку про то, что компилятор не может найти в string оператор = для правого операнда.
явный каст решает проблему
s = (string)a;
но это некрасиво (и неудобно, у меня много объектов А и работы с ними, везде писать в коде явные касты нехорошо)

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

то всё ок

Хмм. Почему в первом случае компилятор не генерит из шаблона оператор для каста в стринг?
А не хочу писать в коде А явный каст, потому что А может работать с любым типом, мне придётся по мере надобности все их вписывать в код, это очень нехорошо.
2 июл 19, 07:07    [21918663]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
CEMb
Почему в первом случае компилятор не генерит из шаблона оператор для каста в стринг?
потому что там не стринг.
Помог шаблонный оператор каста в ссылку на T.
2 июл 19, 07:13    [21918665]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a.guest
Member

Откуда:
Сообщений: 54
CEMb
A a;
string s;
s = a;


Почему ... компилятор не генерит из шаблона оператор для каста в стринг?

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>?
3 июл 19, 04:47    [21919550]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
a.guest
А почему он должен генерить шаблон для каста в стринг а не в const char* или std::initializer_list<char>?
ну вот про это и был вопрос.
почему компилятор сначала ищет оператор= слева, а потом оператор string() справа, а не наоборот?
т.е. с int, например, эта конструкция работает. Если бы компилятор поискал у моего класса оператор каста и нашёл бы его, всё собралось бы Картинка с другого сайта.
3 июл 19, 12:05    [21919715]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a.guest
Member

Откуда:
Сообщений: 54
CEMb
Помог шаблонный оператор каста в ссылку на T.
Это как? У меня не помогает.
#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
}
3 июл 19, 13:43    [21919829]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a.guest
Member

Откуда:
Сообщений: 54
CEMb
a.guest
А почему он должен генерить шаблон для каста в стринг а не в const char* или std::initializer_list<char>?
ну вот про это и был вопрос.
почему компилятор сначала ищет оператор= слева, а потом оператор string() справа, а не наоборот?
Что значит "сначала" и "потом"?
3 июл 19, 13:54    [21919841]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
a.guest
Это как? У меня не помогает.
там надо оба оператора в T и в T&. Я не знаю, почему, хорошо было бы, если бы кто-то объяснил :(

a.guest
Что значит "сначала" и "потом"?

ну вот как там идёт семантический разбор? Я не знаю. Находит выражение "=", потом смотрит, что слева и что справа? У меня в коде 2 варианта, получается
1. искать оператор = у string, который принимает на вход класс А (и не найти)
2. искать оператор string у класса А, чтобы он вернул строку, которая подходит для "=".
где в стандарте написано, что компилятор идёт первым путём?
потому что если я явно указываю каст в string - всё работает, т.е. компилятор идёт вторым путём.
4 июл 19, 06:20    [21920401]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
я тут пытаюсь опять сделать класс, который:
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&& и так далее), а нам этого не нужно.
Собственно, "всё хорошо" получилось. Бонусом (ненужным) получилось так, что в одном параметре можно хранить значения разных типов.

Param p;
p = 1;
p = "a";
int i = p;
string s = p;
// i = 1, s = "a"

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

Ну и отладка всего этого дела весьма сложна - данные все сидят внутри методов, их просто так не посмотришь.
4 июл 19, 07:01    [21920405]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2979
CEMb
Вручную рисовать UI под 50 параметров, где ещё всякие надписи и тултипы - не наш путь Картинка с другого сайта.
два варианта альтернативных:
1. Именно проектирование руками в дизайнере по ГОСТ конкретной формочки. То есть проектирование. АРМ.
2. Обычно в ГУИ есть контрол типа вертикальный грид. Он по модели сам отображает разные типы в ГУИ. То есть в модели информации о типах и на VIEW просто отрисовка в строках или пикселях.
Имхо
4 июл 19, 07:19    [21920411]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7896
CEMb
проблема универсальности в том, что когда мы создаём универсальный класс Param<T>, всё хорошо, до тех пор, пока нам не понадобится складывать его в контейнеры. Потому что контейнеры сразу накладывают ограничение на T. Отнаследовать Param<T> от интерфейса тоже не спасает, так как интерфейс должен иметь метод Get, который возвращает T.

есть еще третий вариант - идиома Type Erasure.
Если я правильно понял это именно то что вам нужно.
4 июл 19, 08:20    [21920441]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
a.guest
Member

Откуда:
Сообщений: 54
CEMb
a.guest
Это как? У меня не помогает.
там надо оба оператора в T и в T&. Я не знаю, почему, хорошо было бы, если бы кто-то объяснил :(
Ты не удалил `operator string()`. А T& не при чём.
4 июл 19, 09:35    [21920483]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
Cerebrum
есть еще третий вариант - идиома Type Erasure.
Не, она не подходит под третий пункт, определение всего на момент компиляции, потому что:

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

А у меня эта проверка делается в compile time. Так что я крут Картинка с другого сайта.

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

Про отказ-выбор. Это, так-то, уже второй мой вариант решения избавления от типов в контейнерах. Первый на предыдущей странице, там как раз попытка написать свой "контейнер". И там можно по имени/ключу из контейнера достать параметр, который имеет информацию о своём типе. А можно сразу значение по ключу. Но у той реализации есть свои проблемы, она автоматически сортирует все параметры(рекурсивный шаблон в основе). Она в основе имеет конкретный stl-ный контейнер, если нужно другой - нужно новую реализацию. Она требует в объявлении указать, какие типы будут использованы. У неё нету итераторов по всей коллекции, но можно сделать итераторы по типам(и мне этого хватает там, где оно применяется), и они опять же привязаны жёстко к своим типам. Но как статическая-"динамическая" типизация, вышло неплохо, ящетаю Картинка с другого сайта.
4 июл 19, 09:55    [21920510]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963
a.guest
Ты не удалил `operator string()`. А T& не при чём.
ну это в этом примере, а в рабочем коде у меня два шаблонных каста в T и в T&, без них не компилируется :(
4 июл 19, 10:05    [21920522]     Ответить | Цитировать Сообщить модератору
 Re: Пятничная шабонная магия  [new]
CEMb
Member

Откуда: Столько
Сообщений: 1963


Попытался прикрутить к своей задаче, но не судьба - десериалезация из файла на момент компиляции не заработает, боюсь Картинка с другого сайта.

А так, да, у него хорошая шаблонная магия.
1 авг 19, 09:10    [21939479]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: 1 2 3 4 5 6      [все]
Все форумы / C++ Ответить