Здравствуйте, Евгений Музыченко, Вы писали:
Pzz>>В том, что разрастание этого подмножества ограничено компилятором, а не должностной инструкцией.
ЕМ>Ну да, при отсутствии свободы в выборе подмножества, такое естественное ограничение вполне разумно.
К сожалению, как только код становится не твоим личным, и появляется хоть какая-то совместная разработка, используемое подмножество языка имеет тенденцию бесконтролько разрастаться.
Re[7]: Для чего шаблонной функции нужна особая сигнатура?
Здравствуйте, σ, Вы писали:
Pzz>>В том, что разрастание этого подмножества ограничено компилятором, а не должностной инструкцией. Первое работает всегда, второе — никогда.
σ>Для Си тоже могут быть нужны должностные инструкции. А то есть компиляторы с __attribute__((cleanup(...))) и прочими приятными дополнениями.
Лучше всего, конечно, иметь не должностную инструкцию, а тулзу, которая не дает использовать лишнего. Но увы, Си плохо потдается тулингу...
Re[8]: Для чего шаблонной функции нужна особая сигнатура?
Здравствуйте, Pzz, Вы писали:
Pzz>как только код становится не твоим личным, и появляется хоть какая-то совместная разработка, используемое подмножество языка имеет тенденцию бесконтролько разрастаться.
Поэтому я всю жизнь успешно избегаю совместной разработки.
Re[8]: Для чего шаблонной функции нужна особая сигнатура?
Здравствуйте, Pzz, Вы писали:
ЕМ>>Ну да, при отсутствии свободы в выборе подмножества, такое естественное ограничение вполне разумно.
Pzz>К сожалению, как только код становится не твоим личным, и появляется хоть какая-то совместная разработка, используемое подмножество языка имеет тенденцию бесконтролько разрастаться.
Даже в эмбеде для пылесосов в этом нет проблемы
Re[8]: Для чего шаблонной функции нужна особая сигнатура?
Здравствуйте, Pzz, Вы писали:
σ>>Для Си тоже могут быть нужны должностные инструкции. А то есть компиляторы с __attribute__((cleanup(...))) и прочими приятными дополнениями.
Pzz>Лучше всего, конечно, иметь не должностную инструкцию, а тулзу, которая не дает использовать лишнего. Но увы, Си плохо потдается тулингу...
Что, и на базе clang'а ничего нельзя натулить? По твоей логике, плюсы вообще невозможно натулить, ведь они почти всё сишечное вобрали и сверху вагон с тележкой
Re[9]: Для чего шаблонной функции нужна особая сигнатура?
Здравствуйте, пффф, Вы писали:
Pzz>>К сожалению, как только код становится не твоим личным, и появляется хоть какая-то совместная разработка, используемое подмножество языка имеет тенденцию бесконтролько разрастаться.
П>Даже в эмбеде для пылесосов в этом нет проблемы
Так это ж проблема не пылесосов, а программистов. Пылесосу-то все равно.
Re[2]: Для чего шаблонной функции нужна особая сигнатура?
Здравствуйте, B0FEE664, Вы писали:
BFE>Зададимся вопросом: существует ли такой код, для которого этот вызов не будет вызовом функции template<> void f<>(char* p);? BFE>Я, таки, напишу это: не всё так однозначно!
Как раз в данном случае все однозначно, ответ: существует. Вот три варианта, которые выиграют overload resolution — при любом объявлении primary template:
Правда первый создает коллизию с двумя другими, но это не важно в данном случае. Главное, что все три выигрывают у специализации. Еще раз подчеркну, при любом объявлении основного шаблона (совместимом с приведенной специализацией, разумеется).
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>Правда первый создает коллизию с двумя другими, но это не важно в данном случае. Главное, что все три выигрывают у специализации. Еще раз подчеркну, при любом объявлении основного шаблона (совместимом с приведенной специализацией, разумеется).
Такое впечатление, что вы не поняли ни вопроса Евгений Музыченко, ни моего ответа на него. Ну или не дочитали...
Суть в том, что вызов f(p); не вызывает функцию template<> void f<>(char* p); даже если используются исключительно шаблонные функции.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Хотел в одной из библиотек сделать финт ушами: в заголовке оставить объявления нескольких одноименных функций с перегрузкой типов параметров, а в модуле реализовать их общим шаблоном, явно определив версии с допустимыми комбинациями параметров. По замыслу, это позволило бы линковать с ней другие библиотеки без перекомпиляции их исходников. Но оказалось, что [как минимум] VC++ дает шаблонным функциям сигнатуры, отличные от сигнатур обычных функций, и линковки таки не получается.
ЕМ>Какой в этом может быть смысл? Чем функция с определенными типами параметров и результата, реализованная через шаблон, в плане линковки отличается от функции с теми же типами, но без шаблона?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Хотел в одной из библиотек сделать финт ушами: в заголовке оставить объявления нескольких одноименных функций с перегрузкой типов параметров, а в модуле реализовать их общим шаблоном, явно определив версии с допустимыми комбинациями параметров. По замыслу, это позволило бы линковать с ней другие библиотеки без перекомпиляции их исходников.
А вообще, такой финт вполне можно делать и со специализациями, не обязательно брать именно не-шаблонные функции
// явно определив версии с допустимыми комбинациями параметровtemplate <> void mySuperPuperFunction<int>();
template <> void mySuperPuperFunction<char>();
Здравствуйте, B0FEE664, Вы писали:
BFE>Такое впечатление, что вы не поняли ни вопроса Евгений Музыченко, ни моего ответа на него. Ну или не дочитали...
Так и есть. Вопрос не понял, ответ не дочитал. Потому что ответ длинный, а вопрос непонятный. По ответу можно еще как-то догадываться о смысле вопроса, но как тебе удалось распарсить оригинал — это для меня непостижимо. При чем там линковка Люди с котлетами, мухи с попугаями.
P.S. Ну и вдогонку, то, что ты написал, можно было выразить одним предложением: overload resolution выполняется по primary template объявлениям, игнорируя специализации. Связь же с ***ВОПРОСОМ*** по-преженему остается для меня загадкой.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, B0FEE664, Вы писали: BFE>Суть в том, что вызов f(p); не вызывает функцию template<> void f<>(char* p); даже если используются исключительно шаблонные функции.
Я вам еще этюд "в тему" подброшу, так, чтоб у сипипи-фобов припадок случился. Вот вам два примера:
В 20 (ну и в 23) стандарте есть недосказанность, а в C++ ABI популярных компиляторов (gcc / clang / msvc), соответственно, есть БАГ, эксплуатирующий эту недосказанность.
А именно, ограничения (концепты и requires) не попадают в декорированные имена.
Из-за этого можно написать well-formed программу, в которой сам же компилятор нарушит ODR: даст двум разным функциям один и тот же символ линковки.
А потом сойдёт с ума сам (если проинлайнит) или сведёт с ума линкер.
template<class T> void foo() { printf("1"); }
template<class T> void bar() { foo<T>(); } // в этой точке видна только foo #1, поэтому она и вызоветсяtemplate<class T> void foo() requires true { printf("2"); }
template<class T> void buz() { foo<T>(); } // функция с ограничением имеет приоритет, поэтому вызовется foo #2int main() {
bar<void>();
buz<void>();
}
// для разнообразия, попробуйте разнести объявления и определения foo
// и перетащить определения выше-ниже точки инстанцирования, то есть, main().
...думаете вы!
И это, я хочу заметить, дистилированный пример.
Не дистиллированный бахнул, к счастью, не в продакшене, а в домашней работе у студента. У меня глаза вытекли, прежде чем я локализовал проблему.
Мейнтейнеры gcc сперва два года отбивались, говоря, что это ill-formed no diagnostics required и чего вы хотите, а потом взяли паузу на год и вот буквально месяц или два назад признали, что это баг.
А поскольку этот баг затрагивает спецификацию ABI, то его исправление приведёт к поломке огромного количества уже скомпилированных библиотек.
Так что, тут хоть закапывай, хоть выкапывай стюардессу, но раньше 2026 года он исправлен не будет.
Ну и кстати, возвращаясь к исходной теме про шаблоны.
MSVC по этим граблям сходил в 1998 году, когда ещё концептов не было.
Разработчики компилятора верили, что параметры шаблона всегда влияют на сигнатуру функции. (А иначе зачем нужно было шаблон писать? Г — Логика!)
template<class T> void foo(); // тип функции - один и тот же: void()int main() {
foo<int>();
foo<char>(); // фигушки, линкер всё равно возьмёт foo<int>
}
и исправили его в 2005 году.
А до того народ лайфхачил как мог: добавлял невидимые аргументы, засовывал функции внутрь шаблона класса.
Но микрософту было хорошо, они хозяева своей экосистемы, взяли и заявили о несовместимости MSVC 7 и 8, пересобрали все виндовые библиотеки, и готово.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Sm0ke, Вы писали:
К>В 20 (ну и в 23) стандарте есть недосказанность, а в C++ ABI популярных компиляторов (gcc / clang / msvc), соответственно, есть БАГ, эксплуатирующий эту недосказанность. К>А именно, ограничения (концепты и requires) не попадают в декорированные имена.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Это как раз не удивляет. А вот о том, что можно смешивать шаблонные и нешаблонные функции с одинаковыми наборами типов, я давно и прочно забыл, поскольку никогда этим не пользовался. Только вот какой в этом может быть смысл? Разве только перекрыть ранее определенную нешаблонную функцию, но это ж получатся изрядные грабли.
Нешаблонные функции наоборот имеют больший приоритет
ЕМ>Так какие же задачи наилучшим образом решаются именно сочетанием перегрузки и шаблона, где и перегруженные, и шаблонные функции полностью совпадают по типам параметров/результата? И для перегрузки, и для шаблона по отдельности есть множество характерных примеров. Есть примеры именно для данного их сочетания?
Шаблонные функции по типам параметров не могут совпадать полностью с перегруженными функциями. По определению. Полностью совпадать могут, если ты сделал специализацию шаблонной функции, которая по типам параметров будет совпадать с перегруженной функцией. Не уверен, но мне кажется, что в таком случае будет варнинг или даже ошибка
S>>Достаточно вспомнить, что шаблоны в язык добавили сильно позже того, как язык стал мейнстримом. Так что одна из целей того, что у обычных функций есть приоритет над шаблонными, -- это обеспечение той же самой логики работы кода, который был написан до появления шаблонов, при переходе на более свежие версии языка.
ЕМ>То есть, в этом нет никакого глубинного смысла или "наилучшего решения", и все сводится к банальному сохранению совместимости с очень старым кодом, который нет возможности модифицировать?
Синдром поиска голубиного смысла? Чем тебе не нравится банальное сохранение совместимости? Слишком простой ответ?