powered by simpleCommunicator - 2.0.58     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Пятничная шабонная магия
143 сообщений из 143, показаны все 6 страниц
Пятничная шабонная магия
    #39373427
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я надеваю свой шаблонный плащ и шаблонную шляпу...

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

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

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

Код: plaintext
1.
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.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39373534
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbНо я захотел сделать лучше, захотел сделать слабые связи и масштабируемость. При этом решил воспользоваться шаблонной магией, заклинанием:

Код: plaintext
1.
template <typename T> class A : public T {};



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

CEMbВ результате шаблонной магии я вчера развалил себе весь проект напрочь(damage 281 hp per class), т.е. сейчас у меня ни одного работающего класса нет, так как все зависят от D и C.
Так всегда бывает, когда не к месту применяешь заклинания )))
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39374288
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb, умные указатели -- это неуклюжая попытка превратить C++ в подобие managed-языка. При разработке игр на C++ это не особо нужно.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39374302
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb[i]

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

.

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

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

class D;

никакая шаблонная магия тут не нужна.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39374976
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyА с чего вы решили, что это хоть как-то устраняет зависимость? )))Изначальные классы друг о друге ничего не знают.
Пётр СедовCEMb, умные указатели -- это неуклюжая попытка превратить C++ в подобие managed-языка. При разработке игр на C++ это не особо нужно.Умные указатели тут ни при чём, я мог бы использовать что-то другое для связи, это ситуацию не меняет, вопрос же был не про это А игры тут при чём? Как игры или не игры влияют принципиально на разработку?
MasterZivчто уж тут ок? иерархия (классов) на основе вложенности - это как-то странно, это не ок...Ну не иерархия, а зависимость, всё равно всё ок. Иерархия - логическая, т.е. элементы одного класса являются частью другого (членами класса). Иерархия получается логическая.
MasterZivдостаточно сделать лишь forward declaration другого класса, в видеНу я это и имел ввиду, когда говорил об упоминании.
MasterZivникакая шаблонная магия тут не нужна.Почему никто не читает то, что я пишу шаблонная магия нужна была для построения двух как можно более независимых иерархий классов. Это необходимо для более удобной разработки, когда мне надо будет менять базовые элементы в обоих иерархиях. Сейчас зависимости между двумя иерархиями явно присутствуют в классах, это неудобно.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39375037
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А можно пример использования? Чтобы почувствовать всю "крутость" и "загадочность" этой магии.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39375290
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonА можно пример использования? Чтобы почувствовать всю "крутость" и "загадочность" этой магии.ага, если речь про
template <typename T> class A : public T {};
то тут всё просто. Данная конструкция делает надстройку над классом, к которому применяется. Применений тут много, я хочу использовать увеличение информации внутри класса. Есть класс А:
Код: plaintext
1.
2.
class A {
};

делаем шаблон:
Код: plaintext
1.
2.
3.
4.
5.
6.
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 иерархии классов, которые у меня были изначально связаны друг с другом, чтобы потом можно было разрабатывать их независимо. Шаблонизацию я закончил, осталось сделать правильные объявления. Надеюсь.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39375315
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbMasterZivникакая шаблонная магия тут не нужна.Почему никто не читает то, что я пишу шаблонная магия нужна была для построения двух как можно более независимых иерархий классов. Это необходимо для более удобной разработки, когда мне надо будет менять базовые элементы в обоих иерархиях. Сейчас зависимости между двумя иерархиями явно присутствуют в классах, это неудобно.

Для этого шаблонная магия тоже не нужна.
Для этого нужны классические паттерны, к которым шаблонная магия никак не относится.
Итого, у меня уже вырабатывается чёткое подозрение, что ты вообще что-то не то делаешь, что следовало бы.
Но что тебе нужно, я до конца не понял, так что думай сам.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39375339
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivДля этого шаблонная магия тоже не нужна.
Для этого нужны классические паттерны, к которым шаблонная магия никак не относится.
Итого, у меня уже вырабатывается чёткое подозрение, что ты вообще что-то не то делаешь, что следовало бы.
Но что тебе нужно, я до конца не понял, так что думай сам.ну, ТС пусть читает Александреску , он как то же крестил ежа с ужом, собирал патерны на шаблонах.
Так то я вот тоже не понимаю, что человек задумал, но вдруг чем то ему поможет
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39375722
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39375745
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivДля этого шаблонная магия тоже не нужна.
Для этого нужны классические паттерны, к которым шаблонная магия никак не относится.какие?
egorychну, ТС пусть читает Александреску , он как то же крестил ежа с ужом, собирал патерны на шаблонах.ну вот я как раз его и читаю.
Пётр СедовПрочитал вот это:так я и говорю, чтобы было нагляднее :)
Пётр СедовЕсли игровую логику пишут на C++, то значит хотят выжать максимум из железа (по скорости и по памяти), а значит умные указатели лучше не использовать. наверно, получается так. Хотя не уверен, что работа в играх с каким-то внутреигровыми объектами на shared_ptr съест ресурсы железа соразмерно с той же графикой.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39377371
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем, получилось как-то так:

Код: plaintext
1.
2.
3.
// base class A
class CA {
};


Код: plaintext
1.
2.
3.
4.
// AEx with gypotethic B
template <template <typename CA>, class BI> class CAWithB : public CA {
vector<BI<CAWithBI>> m_vb;
};


Код: plaintext
1.
2.
3.
//base class B
class CB {
};


Код: plaintext
1.
2.
3.
4.
// BEx with gypothethic A
template <typename AI> class CBWithAI : public CB {
AI *m_pA;
}


Код: plaintext
1.
2.
// code
CAWithBI<CBWithAI> a;


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

Ну как, стал я шаблонным магом 2-го уровня? о_о
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39388082
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
решил я зайти с другой стороны.
т.е. первая сторона: при объявлении переменной шаблонного класса мы передаём в шаблон все базовые типы и шаблоны используемых классов, и потом в этом шаблоне раздаём типы всем шаблонным-шаблонным параметрам. Это всё хорошо и правильно, потому что это гарантия использования одних типов во всех используемых классах.
другая сторона: шаблон, который должен знать только про один входящий обслуживаемый класс, при этом иногда должен возвращать или работать с типами, с которыми работает этот обслуживаемый класс-параметр. Если более детально, то в первом случае мы инициализируем всё в рамках одной переменной, а во втором, эту переменную(этот тип) используем для создания сервисного объекта. Вот тут тонкое место про типосовместимость: нам по-хорошему не надо заводить в шаблоне параметры для базовых типов, используемых в первом случае, просто потому что есть возможность там задать другие типы. У меня в результате так и получилось: пока я разрабатывал, я в шаблон добавил просто родительские классы, а потом при компиляции "оказалось", что типы этих классов не совпадают с типами классов, с которыми работает обслуживаемый класс.
Ок, поэтому во втором случае полезно передавать только основной класс в шаблон и из него как-то получать типы, с которыми работает этот класс. Если мы работаем как транслятор или посредник-обработчик, т.е. вызываем функции базовых классов или передаём данные базовых типов из обслуживаемого класса наружу, то auto подходит великолепно. Но вот если нам нужны какие-то переменные базовых типов внутри класса, то auto уже не подходит. Я решил использовать decltype. При этом, так как у меня из обслуживаемого класса доступны только функции, можно написать decltype(&f()) и получить тип. И тут у меня два вопроса
1. если функция возвращает shared_ptr<T>, то как из этого типа выдернуть T?
2. почему я не могу сказать decltype(&f()) если f - private или protected? sizeof вроде в таких случая работает.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39388084
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb1. если функция возвращает shared_ptr<T>, то как из этого типа выдернуть T?decltype(foo.get()); же...
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39388182
ermak.nn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbCEMb1. если функция возвращает shared_ptr<T>, то как из этого типа выдернуть T?decltype(foo.get()); же...
Вернет T*, нужно хотя бы decltype(*foo)
Вам не поможет element_type? Т.е. foo.element_type
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39388252
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ermak.nn, да, конечно, я просто навскидку написал общую идею. Спасибо.

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

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
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. всё-таки есть сомнения в идеологической правильности такого подхода
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39390014
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доработал идею полностью на шаблонах сегодня утром, хочется немного высказаться

Для простоты понимания, значит, иерархия была такая, по аналогии:
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, их можно разрабатывать отдельно, что и было целью моего приключения: я хотел иметь возможность фиксировать эти классы на некоторых моментах разработки, а потом мочь заменять их другими с более широким или просто иным функционалом, при этом чтобы другие работали как прежде, а так же мочь возвращаться к прежним классам, если нужно. И теперь я это могу, просто заменив название одного класса на другой в строке декларации объекта :)

И дайте мне уже мой чёртов второй уровень шаблонной магии
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39390351
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Ваша ошибка в том, что вы вместо описания конкретной предметной области пытались в первом посте объяснить все какими-то абстрактными сущностями A B C.
Если бы вы сразу написали про книги, то вам бы сразу и сказали что в сущности Страница не должно быть никакой ссылки на сущность Закладка. И никаких бы циклических ссылок не было бы ))
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39390722
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyВаша ошибка в том, что вы вместо описания конкретной предметной области пытались в первом посте объяснить все какими-то абстрактными сущностями A B C.
Если бы вы сразу написали про книги, то вам бы сразу и сказали что в сущности Страница не должно быть никакой ссылки на сущность Закладка. И никаких бы циклических ссылок не было бы ))
Нет никакой ошибки. Предметную область я добавил в описание для того, чтобы было легче понять логическую связь между классами. Выше я приводил пример с картами. Если писать про А, В, С, никто читать не будет, потому что потеряется на втором абзаце :) читать и одновременно строить и держать в голове абстрактную модель в общем случае тяжело для человека.
Сделать ссылающиеся друг на друга и при этом независимые шаблоны - это была цель. Как альтернатива избавлению от связей в коде. По-моему, получилось отлично: никаких #include, forward declaration, интерфейсов, собирается на момент компиляции. Лучше не бывает!
Где мой диплом шаблонного мага? :) я уже придумал ТЗ на новое заклинание для получения 3-го уровня.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39397103
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я надеваю свой шаблонный плащ и шаблонную шляпу...

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

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

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

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

В результате я опять решил всё сделать на шаблонах. Проблема была в том, что вектор в А должен содержать объекты разных классов. Я решил сделать шаблон, с двумя параметрами, один - базовый класс A, второй - класс Shape, вектор которого я объявил внутри шаблона.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
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 перестанут работать, так как они перекрыты вторым шаблоном, и их не будет видно.
Проблема решается через добавление
Код: plaintext
1.
2.
using S::Compare;
using S::AddShape;


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

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

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

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

Ну и вот простенький примерчик, для наглядности
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
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 информацию о типе! :)
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39399978
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
- а я написал игру, используя шаблоны
- ну и как игра?
- победил на этапе компиляции...


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

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


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

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


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


т.е. в результате должен получиться шаблон с одним входящим параметром. Понятно, что в таком "объявлении" неясно, какой из двух параметров указан, поэтому и вопрос, есть ли какие инструменты в языке, которые позволяют в одной строке указать один из параметров шаблона?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39412928
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbСтатическая альтернатива polymorphic hellВсё можно сделать в разы проще:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
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());

почему никто не сказал?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39413121
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbпочему никто не сказал?
Потому что никто не читает и тем более не улучшает абстрактный код делающий непонятно что
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39413353
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyПотому что никто не читает и тем более не улучшает абстрактный код делающий непонятно что Тема ветки - про изучение шаблонов, я хочу сильно преуспеть на этом поприще. Далее, я два раза придумывал тематические объяснения для структур данных, чтобы было удобнее понимать. И я как раз упомянул, что описание - чтобы было удобно читать не про абстракции.
Последние два поста про формирование блока объектов внутри класса. Никто же не жалуется, что vector<T> - ни о чём? Или паттерны программирования. Тут та же ситуация, я пытаюсь на шаблонах сделать иерархию классов, цель указана три поста назад: 20172805 , но и то, у меня там в качестве примера приведена ситуация собирания и рисования двух классов объектов.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39415170
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я тут пару раз уронил компилятор(ms vc++2013), "внутренняя ошибка, поменяйте строки местами...", и у меня возник вопрос.
можно как-то (ключи?) посмотреть логи сборки, процесс компиляции, в общем, более развёрнуто увидеть причины ошибок?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39415396
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39451336
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А кто знает самый просто способ выдернуть тип шаблонного параметра из класса?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
template<typename T> class C
{};

//...
int main
{
	C<A> c;
	// как извлечь из с имя класса А правильным и желательно простым-красивым способом?
}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39451339
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbА кто знает самый просто способ выдернуть тип шаблонного параметра из класса?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
template<typename T> class C
{};

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


Я знаю только об одном способе
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
template<typename T> class C
{
public:
   using Type = T;
};

//...
int main
{
	C<A> c;
	typename decltype(c)::Type t;
}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39455789
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZ, о, спасиб, я до этого пользовался таким: 20126260

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

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

шаг первый был прост, передаём класс B в качестве параметра в шаблон А и там заводим на него массив, ок.
шаг второй был сложнее, так как при правильной передаче всех шаблонных параметров в обе стороны, описания классов (да просто первая строка декларации) разрастались в геометрической прогрессии. Поэтому оставался один вариант: при создании массива внутри класса, класс сам сообщает его элементам себя в качестве родительского. Это очень компактно и не растягивает декларации классов. Всё ок, но только в случае, если классов два. Дело в том, что в вше приведённом объявлении, класс S передаёт себя в качестве родителя в класс P, но сам он ещё ничего про класс L не знает. И вот, получив родителя с элемента класса P, мы не сможем с него вызвать GetParent.
вот что получилось
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
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

второй день не могу придумать, как малыми силами это победить
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39457337
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
                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() нормально работает. При этом в коде нету виртуальности. Как уболтать компилятор?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39459489
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Кольцо Всевластия несомненно было шаблоном: работало исключительно согласно классу персонажа, которого в него передавали...


Сделал двойным проходом:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
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: если вы не пишите ответы, то закидывайте сюда хотя бы интересные вопросы/код/задачки, касающиеся шаблонной магии
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39479478
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Натолкнулся на такую проблему, есть два класса:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
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:
Код: plaintext
1.
2.
A1<B1<A1>> a;
a.Fill();


Всё ок.

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



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


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

Как быть?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39480085
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Проблема решилась тройным проходом
Т.е. вот в этой строке:
Код: plaintext
1.
shared_ptr<M<L<S<P>>>> m = make_shared<M<L<S<P>>>>();


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


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

Код: plaintext
1.
2.
class A : public enable_shared_from_this<A>
{};



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

Код: plaintext
1.
2.
class B : public A
{}



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

Код: plaintext
1.
2.
class B : public A, public enable_shared_from_this<B>
{}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39487225
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

А вопрос-то в чём ? Хочется -- сделай!
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39487239
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivХочется -- сделай!В том виде, как я написал, не компилируется.
Хочется даже так: чтобы каждый отнаследованный класс T был public enable_shared_from_this<T> неявно.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39487296
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Тут не совсем то, но почитайте )
https://stackoverflow.com/questions/15549722/double-inheritance-of-enable-shared-from-this
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39487390
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky, спасибо
Буду делать по старинке, обычный указатель, закрою все доступы и лишние конструкторы, чтобы можно было проинициализировать 1 раз и буду сидеть бояться. По идее, этот указатель (shared_from_this) передаётся дочернему объекту в конструктор, когда его создаёт этот класс. Т.е. не может быть ситуации, когда ребёнок жив, а родитель нет. Просто хотел сделать всё по-современному :)
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39487501
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Главное помнить, что shared_from_this() нельзя вызывать из конструктора ))
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39487973
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyГлавное помнить, что shared_from_this() нельзя вызывать из конструктора ))Не задумывался про это, но оно и ожидаемо, как и бросание эксепшинами в вентилятор конструкторе.
Посмотрел внутренности. Ага, WeakPtr инициализируется в конструкторе shared_ptr() после того, как выполнился конструктор класса-параметра. До этого он Empty.
Спасибо
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39499652
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вопрос.
Есть нитка классов:


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
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:
Код: plaintext
1.
2.
3.
4.
5.
6.
StObj1 o1;
StObj2 o2;
StaticContainer<StObj1, StObj2> st12;
 
st12.EntityAdd2<StObj1>();
st12.EntityAdd2<StObj2>();


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


C2275 на тип ТЕ. Недопустимое использование типа в качестве выражения.
Не пойму, что сделать...
Цель: если тип не совпадает, передать управление следующему в нитке классу, до тех пор, пока не найдём тип или не кончатся классы.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39499727
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

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


А StaticContainer::EntityAdd2 не шаблонный.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39500045
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky, почему не шаблонный?

Код: plaintext
1.
template <typename TE> void EntityAdd2() {...}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39500145
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Потому что шаблон рекурсивный и в конце рекурсии инстанцируется StaticContainer<TS...> с пустым TS т.е. StaticContainer<> у которого метод нешаблонный.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39500172
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky, так у метода свой, отдельный шаблон на TE
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39500178
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Этот не шаблонный.
Код: plaintext
1.
2.
3.
4.
5.
template <> class StaticContainer<>
{
public:
         void EntityAdd2() {}
};
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39500186
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky, спасибо! :)
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39585541
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не могу красиво решить проблему

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

Код: plaintext
1.
T value_;



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

Код: plaintext
1.
2.
3.
4.
5.
6.
C::SetStrValue(string& strValue)
{
	istringstream strm;
	strm.str(strValue);
	strm >> value_;
}



всё ок, пока не попадается строка с пробелами. std::noskipws не спасает. С ним просто останавливается обработка строки на пробеле, без него из строки пробелы пропадают. Как быть?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39585678
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Сначала надо сформулировать как читать строку - например до ближайшего \n, или до конца потока.
Потом надо создать специализацию для строк, и там применить нужный алгоритм чтения строки.
Для построчного чтения или до произвольного разделителя - std::getline
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39586158
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovskyт.е. делать свой парсер строки? Ну вот не хотелось этого делать. Строковый поток отлично справляется с этими задачи, кроме одного момента про, собственно, саму строку.
Сейчас пробую сделать через SFINAE.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39590844
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
такой вопрос:

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

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
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) компилятор ругается на несовместимость возвращаемого значения, хотя реально его никогда возвращать не будет:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
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);
}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39591036
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
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;
}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39591404
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_dev, интересная идея, спасибо. Я так понял, что даже без структуры Get, просто с кастами оно тоже работать будет?
Но вот typedef у меня не получится применить, так как набор типов в объекте заранее неизвестен, это шаблон, на каждом объекте набор типов определяется параметрами шаблона. Но вот с кастами надо попробовать, спасибо.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39612660
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plaintext
1.
((C*)0)->Get


UB
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39623679
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
можно как-то в качестве параметра шаблона использовать формулу?

что-то типа
Код: plaintext
1.
2.
3.
4.
temlate<typename F> int Do (int a, int b)
{
return F(a, b);
}



А без лябмд?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39623681
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbможно как-то в качестве параметра шаблона использовать формулу?
Можно использовать класс, в котором использовать (статическую) функцию с нужной сигнатурой.
Но вот если у меня F очень плотно используется? Буквально, хочу в одном месте a+b, а в другом a-2*b, например. И таких штук 10-20, не хочется под всё классы городить, и дорого это по производительности.

Ну а с лямбдами-то это можно сделать?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39623792
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbБуквально, хочу в одном месте a+b, а в другом a-2*b, например.инлайнами и опциями компилятора у меня таки это получилось
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624328
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbCEMbможно как-то в качестве параметра шаблона использовать формулу?
Можно использовать класс, в котором использовать (статическую) функцию с нужной сигнатурой.
Но вот если у меня F очень плотно используется? Буквально, хочу в одном месте a+b, а в другом a-2*b, например. И таких штук 10-20, не хочется под всё классы городить, и дорого это по производительности.

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

Код: plaintext
1.
2.
3.
4.
5.
6.
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);});
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624412
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owlда, отлично, даже без inline код встраивается без вызова! Жаль только что у меня проект в 2010, там лямбд нету.

Отдельно порадовал оптимизатор, к примеру do_lamda(rand(), 1, ...) сводится в результате к инкременту. Ну и вообще без rand и проверки возвращаемого значения не удалось собрать, так как оптимизатор не видел смысла в этом коде, просто выкидывал его из релиза
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624580
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest
Код: plaintext
1.
((C*)0)->Get

UBИ что же тут неопределённого для LE?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624592
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_deva guest
Код: plaintext
1.
((C*)0)->Get

UBИ что же тут неопределённого для LE?Что такое "LE"? Little Endian?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624633
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest, да.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624650
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_dev, не понимаю, при чём тут вообще endianness.
null pointer не указывает ни на какой объект, поэтому возможность получать доступ к data member-у сомнительна.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624720
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestrdb_dev, не понимаю, при чём тут вообще endianness.
null pointer не указывает ни на какой объект, поэтому возможность получать доступ к data member-у сомнительна.А где ты видишь доступ к члену экземпляра класса по нулевому указателю?
Код: plaintext
1.
2.
3.
4.
5.
operator const C& () const
{
  register size_t offset = reinterpret_cast<size_t>(&((C*)0)->Get);
  return *reinterpret_cast<const C*>((size_t)this - offset);
}

Это банальный расчёт смещения члена внутри структуры экземпляра класса, чтобы инкапсулированный объект мог получить указатель на инкапсулирующий.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624732
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_deva guestrdb_dev, не понимаю, при чём тут вообще endianness.
null pointer не указывает ни на какой объект, поэтому возможность получать доступ к data member-у сомнительна.А где ты видишь доступ к члену экземпляра класса по нулевому указателю?Здесь:
Код: plaintext
1.
((C*)0)->Get


rdb_dev
Код: plaintext
1.
2.
3.
4.
5.
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
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624750
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestrdb_devпропущено...
А где ты видишь доступ к члену экземпляра класса по нулевому указателю?Здесь: [src c++]
((C*)0)->GetЕще раз повторяю - в моём нет доступа к члену объекта по нулевому указателю - нет ни чтения структуры, ни вызова функции. Учите C++ ABI !
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624758
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_deva guestпропущено...
Здесь: [src c++]
((C*)0)->GetЕще раз повторяю - в моём нет доступа к члену объекта по нулевому указателю - нет ни чтения структуры, ни вызова функции. Учите C++ ABI !prog.cc:29:58: runtime error: member access within null pointer of type 'C'
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624768
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plaintext
1.
((const C&)*this).a_;


UB
Код: plaintext
1.
((const C&)*this).b_;


UB
Код: plaintext
1.
((const C&)*this).c_;


UB
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624793
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest, еще и с перегрузкой операторов приведения типа не знаком?
Собрать на g++ и пройтись отладчиком - не судьба?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624803
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_dev, ой-ой. Изв е ните. Оператор приведения типа же определён.

Который весь сплошь из УГ UB состоит. Даже если заменить
Код: plaintext
1.
reinterpret_cast<size_t>(&((C*)0)->Get)

на offsetof (который до C++17 для данного класса был UB, а теперь "conditionally supported") и он будет supported в данной реализации, то арифметика "указателей" там — останется UB.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624804
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_devСобрать на g++ и пройтись отладчиком - не судьба?Принести сюда цитат из стандарта, которые покажут, что код ­валиден — не судьба?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624812
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guest, еще раз - где здесь доступ к члену экземпляра класса (чтение свойства/вызов метода) по нулевому указателю экземпляра?
Код: plaintext
1.
2.
3.
4.
5.
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" - это что? Амперсанд (взятие адреса) видим?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624816
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestrdb_devСобрать на g++ и пройтись отладчиком - не судьба?Принести сюда цитат из стандарта, которые покажут, что код ­валиден — не судьба?Этот код валиден даже для структур чистого Си. Открывай раздел ABI стандарта и читай!
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624887
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_devОткрывай раздел ABI стандарта и читай!Что-то не найду в http://eel.is/c draft/ раздел "ABI".
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624892
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624902
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyВ стандарте (всех версий), разыменование нулевого указателя упоминается как пример UB. (С++17 8.3.2.5).В какой версии драфта пункт 8.3.2.5?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624930
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky, а где написано, что нельзя разыменовывать указатель с адресом 0x0 (не путать с указателем NULL, который хоть и представлен во многих компиляторах именно как (void*)0)?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624940
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_devгде написано, что нельзяВ C++ так вопрос не ставится. В C++ спрашивается "где определено поведение такой-то конструкции?". А если оно не определено — то получается неопределённое поведение.

rdb_devуказатель с адресом 0x0Можно узнать способ получения указателя с адресом 0x0?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624949
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_dev
Код: plaintext
1.
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.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624952
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestrdb_devуказатель с адресом 0x0Можно узнать способ получения указателя с адресом 0x0?Можно! Открой заголовочные файлы гнуса и узри в них:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
#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 */



Но лично я предпочитаю что-то типа:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
    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
      }
    .
    .
    .
    };
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624960
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestrdb_dev
Код: plaintext
1.
struct __Get;


http://eel.is/c draft/lex.name#3In 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.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
__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;
}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624967
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_deva guestпропущено...
Можно узнать способ получения указателя с адресом 0x0?Можно! Открой заголовочные файлы гнуса и узри в них:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
#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Но лично я предпочитаю что-то типа:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
    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
      }
    .
    .
    .
    };

А тут?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624970
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_devТы найдешь пренебрежение этой рекомендацией даже в исходниках RHEL, не говоря уже о заголовочных файлах реализации cstdlib.
1. Стандарт резервирует идентификаторы определённого вида для реализации.
2. Реализация (в данном случае — cstdlib) использует идентификаторы данного вида.

Как ты в следовании этой рекомендации смог увидеть пренебрежение ею?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624985
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestНу и в какой конкретно строчке получается указатель с адресом 0x0, но при этом не нулевой указатель?Поясняю для непонятливых - адреса с 0x0 по 0x0000FFFF в ОС Windows для x86 являются инвалидными только благодаря самой реализации ОС, в которой при доступе по этим адресам возникает исключение page fault, но это не значит, что эти адреса инвалидны в реализациях любых ОС, в т.ч. проприетарных или в реализациях прошивок контроллеров, которые могут хранить по этим адресам некие заранее известные структуры данных по заранее известным смещениям. Поэтому, валидно любое приведение любых адресов в арифметике указателей, чтобы там не насочиняли стандартописатели.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39624989
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_devвалидно любое приведение любых адресов в арифметике указателейМожно цитаты из стандарта?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625003
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestrdb_devвалидно любое приведение любых адресов в арифметике указателейМожно цитаты из стандарта?Цитаты из стандарта о том, что для процессоров и контроллеров валидны все доступные им адреса памяти?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625007
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devAnatoly 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
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625012
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devЦитаты из стандарта о том, что для процессоров и контроллеров валидны все доступные им адреса памяти?
То что адрес 0 это такой же адрес для процессора как и другие не противоречит тому что в С++ обращение по этому адресу - UB.
Из С++ обращаться к нему нельзя, а из ассемблера например можно.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625016
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly Moskovskya guestВ какой версии драфта пункт 8.3.2.5?
n4594, 8.3.2 параграф 5Хм. Но ведь это не Anatoly Moskovskyразыменование нулевого указателя упоминается как пример UB.Там написано что UB это инициализация ссылки выражением `*p` если `p == nullptr` (ну или вообще инициализация не валидным указателем на объект).
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625018
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovskyrdb_devAnatoly 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, а именно неинициализированный указатель.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625019
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
a guestинициализация не валидным указателем на объектинициализация выражением, которое не обозначает валидный объект.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625025
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devМожно! Открой заголовочные файлы гнуса и узри в них
Внутри кода стандартной библиотеки могут быть какие угодно хаки, не всегда даже являющиеся С++.
Так что не стоит оттуда брать примеры ))
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625026
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guesta guestинициализация не валидным указателем на объектинициализация выражением, которое не обозначает валидный объект.А какая разница? Представь, что ты пишешь на Си часть прошивки к контроллеру, а до тебя разработчики, что писали, к примеру boot loader на ассемблере, поместили в начальные адреса адресного пространства некие статичные инициализированные в бутстрапе структуры данных. Зная о формате этих структур, ты как к ним будешь доступ получать?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625029
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyВнутри кода стандартной библиотеки могут быть какие угодно хаки, не всегда даже являющиеся С++.
Так что не стоит оттуда брать примеры ))Без "грязных хаков" на Си/С++ системные вещи вообще не пишутся! Есть идеалисты, придумывающие стандарт, которому рекомендовано следовать, а есть программисты, которые вынуждены обходить ограничения стандартов.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625039
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devНет! В стандарте не сказано, что null указатель, это тоже самое, что (void*)0
Нет конечно, там сказано что (void*)0 дает null указатель. То, с чем вы пытаетесь спорить.
rdb_devИменно по этой причине в стандарт введен null указатель, который совсем не (void*)0, а именно неинициализированный указатель.
Ггггг.
Нет. Основная причина это корректные перегрузки функций.
Со старым NULL:
Код: plaintext
1.
2.
3.
void f(char*);
void f(int);
f(NULL); // ошибка: не понятно что вызывать (обе функции могут быть вызваны), хотя в большинстве случаев имеется в виду вызов f(char*)


С nullptr:
Код: plaintext
1.
2.
3.
void f(char*);
void f(int);
f(nullptr); // вызывается f(char*), как и задумывалось
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625073
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625077
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky[/src]
С nullptr:
Код: plaintext
1.
2.
3.
void f(char*);
void f(int);
f(nullptr); // вызывается f(char*), как и задумывалось

Еще не могу понять, каким образом компилятор C++ должен "дедуктировать", что тип std::nullptr_t , подходит для вызова функции void f(char*)?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625115
a guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_devНикак не могу разглядеть - в каком месте тут UB?Да никто и не говорил, что UB из-за каста нуля к указателю.
Ты, похоже, вообще не понимаешь, что тебе пишут.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625145
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devНикак не могу разглядеть
rdb_devЕще не могу понять
Похоже нет смысла продолжать. ))
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625281
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a guestrdb_devНикак не могу разглядеть - в каком месте тут UB?Да никто и не говорил, что UB из-за каста нуля к указателю.
Ты, похоже, вообще не понимаешь, что тебе пишут.Алилуия!
Я надеюсь, п.1 параграфа 4.11 стандарта достаточно доходчиво объясняет что, к чему и как может быть приведено?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625284
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyПохоже нет смысла продолжать. ))Ну еще бы!...
Напомни еще разок, что так к чему приводить - UB? :)
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625347
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovskyrdb_devЕще не могу понять
Похоже нет смысла продолжать. ))На счёт "deduction" nullptr для выбора void f(char*) соглашусь - вчера затупил... :) Но на счет якобы UB при конвертации (size_t)0 к типизированному указателю на экземпляр структуры/класса/члена совершенно не согласен.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625412
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devНо на счет якобы UB при конвертации (size_t)0 к типизированному указателю на экземпляр структуры/класса/члена совершенно не согласен.
UB не тут. Но смысла дальше объяснять нет, т.к. уже не раз пытались. Кто захотел - понял, а кто не понял тот поймет )))
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39625500
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky, подытожим? :)
Anatoly Moskovskyrdb_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 уже не будет являться доступом к экземпляру класса и/или члену экземпляра. Стандарт же не идиоты писали!
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39710236
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я надеваю свой шаблонный плащ и шаблонную шляпу...

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

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

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
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.). Но отдельных функций работы с ними много и они большие(циклы, перевызовы других функций, логика разбора), поэтому рекурсивное определение шаблонов тут вообще неудобно делать. Вот и думаю, как бы это сделать. У Александреску вроде было что-то такое в Локи, но не уверен, что оно сильно от рекурсивного объявления отличается.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39710237
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Тебе нужны boost::mpl::vector и boost::mpl::for_each.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39711386
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZ, о, спасибо, не знал, что такое есть. В сопутствующей доке этого не нашёл (в интернете есть).

У меня там основная проблема была в выносе кода в отдельные функции. Всё-таки не поленился и вынес...
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39711398
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

Советую к прочтению Advanced Metaprogramming in Classic C++ by Davide Di Gennaro . Там такие финты ушами описаны, после которых и жить не хочется,
когда ты знаешь что где-то это может применяться. У тебя сразу все вопросы отпадут касательно реализации Boost MPL.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39712184
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZТам такие финты ушами описаны, после которых и жить не хочется,
когда ты знаешь что где-то это может применяться. У тебя сразу все вопросы отпадут касательно реализации Boost MPL.
Хм, это интересно :)
Мне где-то попадались финты: люди сделали тетрис в потоке отладки сборки проекта
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39712238
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbNekZ, о, спасибо, не знал, что такое есть. В сопутствующей доке этого не нашёл (в интернете есть).

У меня там основная проблема была в выносе кода в отдельные функции. Всё-таки не поленился и вынес...Если мне не изменяет память, for_each вкрячили в стандарт C++14. В GCC он точно есть.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39712240
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devЕсли мне не изменяет память, for_each вкрячили в стандарт C++14. В GCC он точно есть.
for_each по вектору из типов ?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39712263
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZ,
Цитата из stl_algo.h (#include <algorithm>)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
  /**
   *  @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.
    }

...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39712289
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devNekZ,
Цитата из stl_algo.h (#include <algorithm>)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
  /**
   *  @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 является шаблонным типом, а не функцией.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39734747
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня вопрос про специализацию метода шаблона.

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

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
emplate<typename T> class C
{
public:
	C<T>(){} // body in
};

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



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

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
emplate<typename T> class C
{
public:
	C<T>();
};

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

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


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

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

и почему оно собирается, когда специализация находится в заголовочном файле?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39734750
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
template<typename T>C<T>::C() // body out, fixed
{}

И это MS VC++17
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39734755
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbесли вынести специализацю в cppто код для не неё не собирается. Странно.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39734783
Фотография Cerebrum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbесли вынести специализацю в cpp(вроде это же явный код, там ему и место)
если хочешь, чтобы конструктор для специализации был в cpp попробуй вынести в cpp
Код: plaintext
1.
template class C<string>;
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39734788
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

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



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



Почему не так?
Код: plaintext
1.
2.
3.
// string impl
template<> C<string>::C()
{}



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



А таким cpp-шник:
Код: plaintext
1.
2.
3.
template<> C<string>::C()
{
}



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

NekZА заодно, раз уж ты ограничиваешь инстанциации шаблона, то сделай это на уровне компилятора, а не линкера,
либо через SFINAE, либо явным путём всех возможных специализаций всего класса в хедере.Мне нужно просто переопределить один метод для одного типа(в качестве параметра шаблона). SFINAE, конечно, можно приделать, но это слишком для такой простой ситуации. Мне надо вот, как тут , но код общей функции print вынести из описания класса.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39734812
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZА таким cpp-шник:А, да, если код в cpp - он не собирается, т.е. компилятор его игнорирует.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39734926
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbNekZА таким cpp-шник:А, да, если код в cpp - он не собирается, т.е. компилятор его игнорирует.
Друг, ну что за формулировки? Наверное, ты имел в виду линкер?
Кстати, можно было бы попробовать трюк с extern template.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39735394
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZДруг, ну что за формулировки? Наверное, ты имел в виду линкер?Нет, именно компилятор. Конечного(скомпилированного) кода нет. Если я ставлю в cpp-коде брекпоинт, среда его убирает с формулировкой, что по этому cpp-коду не было ничего собрано. Тогда как брекпоинт в заголовке ставится и отрабатывает - код есть.
NekZКстати, можно было бы попробовать трюк с extern template.Нет, надо разобраться в вопросе :) Там должно быть всё просто. Я сейчас возьму таймаут(много работы) и чуть позже спокойно посмотрю, почему оно так и как оно должно быть. А пока сделаю, чтоб просто работало :}
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39815179
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbЯ сейчас возьму таймаут(много работы) и чуть позже спокойно посмотрю
ты сам в это веришь?У меня вопрос:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
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?
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39815216
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
код для большего понимания ситуации:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
// 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;
	}
};



Код: plaintext
1.
2.
3.
4.
5.
6.
// 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: если до вечера не найду решение, то буду использовать передачу параметра в функцию и неявную специализацию. И страдать от того, что всё в две строчки, а могло быть в одну.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39815310
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Проблема решилась переносом using-ов в хвост класса. Видимо, как-то так работает построитель классов, видимость устанавливается после того, как развернут метод, а не до того. Ну, т.е. можно и до того, но это должен быть готовый метод в классе-предке. А тут его ещё не было.
...
Рейтинг: 0 / 0
Пятничная шабонная магия
    #39815316
Фотография Cerebrum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb,

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

и еще

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

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


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

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

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


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

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


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

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

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


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


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

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


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

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

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


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

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

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


то всё ок

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



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

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

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

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

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

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

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

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

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


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

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

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

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


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

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


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