|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
|||||||||||||||||||||||||||||||
[дизайн и эволюция] провалы в variadic конструкторы13.01.2016, 04:36. Показов 3363. Ответов 29
Метки нет (Все метки)
всем привет.
уже несколько человек обращались ко мне по почте, с просьбой помочь разобраться с variadic конструкторами. я закобался отвечать каждому персонально, и решил создать эту тему. что бы в будущем можно было бы просто предоставлять перманентный линк. Часть 1. проблема следующая: variadic конструктор способен принять аргументы любых типов, и в любых количествах. в него проваливается все подряд, включая аргументы такого же типа. то бишь, вместо запуска конструктора копии, или перемещения, запускается вариадик. следующий пример иллюстрирует эту проблему: http://rextester.com/KDQKW21505
стандарт гарантирует, что обычные сишные функции-элипсисы (функции с переменным количеством аргументов, вида: return_type func( ... ); ) всегда вызываются в самую последнюю очередь. то бишь они имеют самый низкий приоритет на конкурсе отбора претендентов на перегрузку. и все счастливы. однако, по не понятной для меня причине, тоже самое для вариадиков не сделали. в отличие от сишного элипсиса, вариадики участвуют в конкурсе на общих основаниях. это значит, что к нему применяются точно такие же правила, как и к обычным шаблонно-функциям. теперь немножко о конкурсе: сначала предпочтение отдается не-шаблонным версиям функций. если среди них есть такая, которая подойдет под аргументы, без необходимости кастить типы, то именно она и будет выбрана. но если аргумент не подходит к параметру функции без каста, то считается, что шаблонная версия подходит лучше, потому что шаблонная версия позволяет избежать каста. теперь вернемся к нашему примеру-иллюстрации, и добавим туда конструктор, который способен принять аргумент без каста: http://rextester.com/QKP5835
1. самое главное, это нужно понять: что квалификатор const - неотъемлимая часть типа. тип с квалификатором и такой же, но без него - это два принципиально разных типа. это различие фиксируют шаблоны, и перегрузки. 2. если тип аргумента без каста не подходит к параметру не шаблоной функции, то она уже проигрывает конкурс шаблонной. Добавлено через 16 секунд Часть 2. однако это все лирика, а нам нужен наш вариадик, и нужно, что бы наши конструкторы копии и перемещения работали нормально. как этого можно достичь? есть два пути решения этой проблемы: 1. самый простой способ: вляпать нестандартные конструкторы. и подавить предупреждения от компиляторов. это работает в большинстве случаев. однако, компиляторы не зря кидаются предупреждениями. и в некоторых редких случаях можно огребсти. по сути, нестандартный конструктор вносит в код этакое "UB". однако, в данной теме я не буду рассматривать эти случаи. 2. техника sfinae. это более сложный, зато - грамотный, и надежный. именно так эта проблема решается в профессиональных библиотеках, например - в boost. рассмотрим его поподробнее: однако, сначала, для упрощения материала, мы рассмотрим его на примере с одним шабонно-параметром: способ заключается в том, что применив немножко шаблонно-магии, можно запретить инстанцирование шаблоно-функции для случая, когда T совпадает с именем класса, и тогда она выпадет из конкурса претендентов. и у компилятора не останется иного выбора, кроме как рассмотреть не-шаблонные версии, пусть даже и с кастом. и он находит конструктор копии, или перемещения. оффициально данная техника называется "sfinae", по одноименному свойству шаблонов: не запарывать компиляцию в случаях, когда очередная шаблоно-функция вывалилась из конкурса. пример: http://rextester.com/SOAZP16444
нужно тоже самое сделать и для конструктора перемещения тоже. давайте модернизируем нашу sfinae-резалку: http://rextester.com/FVAU27980
однако, для полноценной работы этого ещё не достаточно. данная конструкция сломается сразу же, как только возникнет наследование: http://rextester.com/BZRR35485
наследник без проблем кастится к базовому. но в нашем случае любой каст - это провал в шаблонно-конструктор. поэтому, необходимо порезать шаблон не только для текущего класса, но и для всех его наследников. для этого модернизируем нашу конструкцию: http://rextester.com/OEBD97935
и это - хорошая новость.
15
|
|||||||||||||||||||||||||||||||
| 13.01.2016, 04:36 | |
|
Ответы с готовыми решениями:
29
Дизайн и эволюция: перегрузка макросов [Дизайн и эволюция] Дискриминация шаблона на примере макроса OUT_TO_STREAM
|
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
|||||||||||
| 13.01.2016, 04:36 [ТС] | |||||||||||
|
Часть 3.
способ для 1 параметра шаблона отлично работает. и это - хорошая новость. плохая заключается в том, что это работает только, и только для 1 параметра шаблона. и не работает для вариадиков. дело в том, что мы заранее не знаем, сколько параметров будет у вариадика. ситуация усугубляется ещё и тем, что их может не быть вообще. (пустой конструктор, например) мы не можем просто так взять, и вычислить тип последнего параметра. (на самом деле можем, если поприседать вокруг мета-программинга. но конструкция получится замороченной) самое ужассное заключается в том, что мы не можем подмешать параметр, выводимый по умолчанию после вариадик-пака, как мы это делали для 1 параметра. в общем, решение для 1 параметра не сработает в вариадиком в принципе. то есть вообще не сработает. однако решение существует. и для того, что бы понять, как это работает, я и сделал такую подробную пошаговую иллюстрацию для одного параметра. немножко о конкурсе шаблоно перегрузок: если есть шаблоно-вариадик, и просто шаблон с фиксированным количеством параметров, то предпочтение будет отдано второй версии при условии, что количество параметров точно совпадает. решение проблемы вариадиков заключается в том, что бы создать дополнительно шаблоно-конструктор с одним параметром. и тогда все возможные провалы по 1 параметру попрут на него. к сожалению, мы не сможем порезать шаблон с 1 параметром, как мы это делали выше. потому что если порежем, то шаблон вылетит из конкурса, и мы опять провалимся в вариадик конструктор. суть решения не в том, что бы порезать шаблон с 1 параметром. а в том, что бы перенаправить его на нужные нам конструкции. итак, знакомьтесь с новой техникой с++11: делегирующие конструкторы: http://rextester.com/ADMR12889
и вуаля! вариадик взят под контроль. теперь дело осталось за малым: нужно привести код в более менее читабельное состояние, и так, что бы его можно было бы использовать повторно. лично я для подобных целей завел библиотеку под названием что в переводе на русски, должно означать "обходной путь": итоговое решение: http://rextester.com/FUHG59360
которые данный код не учитывает. например: const rvalue, ну или volatile какие нибудь. но это редкие кейсы. я думаю нет смысла из-за них усложнять и без того мало мало замороченное клюкало. к тому же, архитектура selector`a специально ориентирована на возможные расширения. поэтому, вы всегда сможете его модернизировать, и обыграть какой нибудь дополнительный кейс.
10
|
|||||||||||
|
|
||||||
| 13.01.2016, 10:28 | ||||||
|
hoggy, а для чего 2 раза
remove_reference в этих конструкциях
Добавлено через 2 часа 24 минуты Не по теме: hoggy, я не с целью очередной спор затеять, я действительно спрашиваю :)
0
|
||||||
|
Игогошка!
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
|
|
| 13.01.2016, 10:40 | |
|
hoggy, на кой фиг нужны вариадик конструкторы и весь этот костыль, если можно написать конструктор, который просто принимает std::initializer_list<T>?
0
|
|
|
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
|
|
| 13.01.2016, 10:50 | |
|
0
|
|
|
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
|
|
| 13.01.2016, 11:01 | |
|
Variadic constructor -- это уже откровенный провал дизайна, ибо любой конструктор -- это преобразование типов, коих можно написать счётное число. В классе им не место. В классе достаточно явно описать один, конструктор-инициализатор, для остального есть фабрики.
Хотя, наверно, с точки зрения возможностей C++11 поковырять подобную ситуацию интересно...
0
|
|
|
Игогошка!
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
|
|||
| 13.01.2016, 11:05 | |||
Не?Какие вообще use-cases? С этого стоило бы начать.
1
|
|||
|
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
|
||
| 13.01.2016, 11:10 | ||
|
0
|
||
|
Неэпический
|
||
| 13.01.2016, 11:12 | ||
![]() Да и сколько должно быть этих списков? ![]() Ну, собственно, согласен mporro. Думаю, такой костыль не стоит усилий, потраченных на него, хотя хз что может приключиться. Но в любом случае, спасибо hoggy за весьма интересную тему, коих на форуме почти никогда не бывает. В основном тут "памогите решить, утром зачет, а задания дали только ночью, некада читать первую главу книги". Так что в любом случае плюсик автору.
0
|
||
|
Игогошка!
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
|
|||
| 13.01.2016, 11:17 | |||
![]()
0
|
|||
|
|
|
| 13.01.2016, 12:00 | |
|
По вопросу использования - как вариант можно дергать делегирующие конструкторы, которые будут дергать другие делегирующие конструкторы, таким образом программист может регулировать порядок инициализации членов передавая в конструктор аргументы в разном порядке.
И еще про "зачем это надо" - если бы добавили вариадики, но не добавили возможность конструкторам их использовать, то на всех С++ ресурсах было бы много негодования на тему "почему везде можно, а в конструкторе нет", не смотря на то, что пользы от этого мало
1
|
|
|
Игогошка!
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
|
||||||||||||
| 13.01.2016, 15:34 | ||||||||||||
Можно пример кода?![]() ![]() ![]() Я немного пошукал в инете: 1) Если можно обойтись списком инициализации, то так и лучше делать. 2) Этот конфликт между конструкторами предлагалось разрешить, но комитет сказал: есть sfinae, а скоро будут концепты, поэтому нафиг. 3) Ребята на stackoverflow считают, что нестандартные конструкторы предпочтительнее sfinae. PS Я особо не разбирался, сейчас времени нет, но если написать вот так, то конкретно в данном примере выдаст точно такой же результат (вариадик не работает, если аргументов нет или есть один аргумент, который кастится):
3
|
||||||||||||
|
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
|
|||||||
| 13.01.2016, 19:28 | |||||||
|
Кликните здесь для просмотра всего текста
6
|
|||||||
| 13.01.2016, 19:54 | |
|
0
|
|
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
||||||||||||||||||||||||
| 13.01.2016, 20:26 [ТС] | ||||||||||||||||||||||||
|
универсальная ссылка схлопывалась до простого референса. сейчас это, наверное, уже не актуально. область применения вариадиков - различные статические фабрики, корежи, делегаты, и тп вещи. её ценность соизмерима с ценностью decltype, на мой взгляд, это будут разные списки из одинаковых типов. однако на практике требуются списки из разных типов. вообще, из-за своего органичения, инициалайзер лист оказался не очень востребованным. конструктор с ним - диковинка. а вот вариадики - слошь и рядом. потому что практичны. даже несмотря на корявость с конкурсом перегрузок. вместо этого представьте себе ситуацию: "я не знаю ранее, что там может быть". наприммер: диначический делегат. имеет дизайн:
методы, с учетом биндинга аргументов, и тп. при этом изначально, заранее, не известно на что именно его будут нацеливать. я такую штуку делал ещё под с++03. вариадиков мне люто не хватало. пришлось применить тяжелую артилерию на макросах. ну или вот, тоже из личной практики, паттерн "домики":
от которой наследуются другие формы. базовая форма отвечает за механику построения дерева. кроме того, базовой форме в свою очередь так же можно указать базовый класс. так называемый "интерфейс форм". это нужно для того, что бы в конкретном случае была возможность указать интерфейс, от которого будут унаследованы все виджеты. а это в свою очередь нужно, что бы можно было бы не просто формировать деревья, но и обработать все его узлы, посредством интерфейса спроектированного под ключ конкретной задачи. получается, что базовая форма выступает в качестве статической фабрики. при этом она не знает, какие будут наследники, и каким будет базовый класс. однако должна быть готова к тому, что бы удовлетворить все их потребности. вообще, при желании, примеров можно привести массу. я выделил шаблоно-конструкторы с одним параметром, который можно было проанализировать. это - универсальное решение я знаю ещё один способ. может быть он даже попроще будет. но он требует явного наличия дефолтного конструктора. и кстати, ребята спрашивали, зачем такое может понадобится. вот этот способ я открыл по практическим соображениям. пример-иллюстрация - дизайн решения реальной задачи. есть некая хитрая смарт-обертка, которая помимо прочего позволяет версионировать ресурс. можно одновременно модифицировать, и сохранять ресурс на диск, например. это не важно. суть в том, что она должна уметь сконструировать захватываемый ресурс. причем, последним аргументом можно указать кастомный аллокатор. тогда будет другой сценарий действий. http://rextester.com/WNJIT27551
как можно в шапке шаблона анализировать строение вариадик-пака. правда цена за это - явно указанный дефолтный конструктор.
3
|
||||||||||||||||||||||||
|
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
|
||||||
| 02.08.2016, 01:33 | ||||||
|
hoggy, я тут помозговал... вот вполне юзабельное решение , правда допиливать надо, ибо я так и не смог устранить проблему с конструктором копии:
0
|
||||||
|
Неэпический
|
||||||
| 02.08.2016, 08:21 | ||||||
|
Как вариант:
1
|
||||||
| 02.08.2016, 08:21 | |
|
Помогаю со студенческими работами здесь
20
Variadic Templates - как обращаться к аргументам variadic-функции? Webpack собирает проект, а приложение говорит что мои конструкторы не конструкторы Провалы в работе wi-fi Управление BLDC и провалы по напряжению
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Налог на собак: https:/ / **********/ gallery/ V06K53e
Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf
Пост отсюда. . .
|
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop?
Ниже её машинный перевод.
После долгих разбирательств я наконец-то вернула себе. . .
|
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод
Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод.
Thinkpad X220 Tablet —. . .
|
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта
Симптом:
После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
|
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
|
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|