Здравствуйте, Conr, Вы писали:
C>В свежей студии (VS 2017 15.8) можно уже спокойно использовать <type_traits>, они специально для драйверистов его почистили
Читал, но переходить на свежие студии (как и на Win10) буду только после того, как на VS 2008 и Win10 станет совсем невмоготу. Нечеловеческие они.
Re[7]: Не могу явно инстанцировать шаблон функции-члена
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Мне кажется, что для функций с тремя-четырьмя параметрами это будет неимоверно громоздко. Например, у меня есть функция MulAddDiv, вычисляющая выражение "(a * b + c) / d" с использованием особенностей x86 (команды перемножения 32-разрядных в 64-разрядное, и обратный вариант деления). Соответственно, для 32-разрядных типов используется эта реализация, а все остальные варианты, имеющие хотя бы один 64-разрядный параметр, реализуются "втупую".
Если аргументов несколько, то опция по сути только одна
template<typename T1, typename T2 , typename T3> Res f(T1 a, T2 b, T3 c);
т.е. иметь столько параметров шаблона, сколько и аргументов.
Предложенный селектор можно специализировать для аргументов-целых чисел, разрядностью меньше чем 32 и чисел разрядностью больше 32. Но это будет больше писанины и использования стандартной библиотеки (потребуется is_integral из type_traits и всякое из <limits>)
Здравствуйте, andyp, Вы писали:
A>т.е. иметь столько параметров шаблона, сколько и аргументов.
A>Предложенный селектор можно специализировать для аргументов-целых чисел, разрядностью меньше чем 32 и чисел разрядностью больше 32. Но это будет больше писанины и использования стандартной библиотеки (потребуется is_integral из type_traits и всякое из <limits>)
Вот меня и вымораживает то, что вместо адекватных языковых средств управления приоритетами и доступностью шаблонных функций, идеологами C++ предлагаются извращения через метапрограммирование. По сути, это костыли, и выглядят уродливо, хотя и работают как-то. Очень трудно заставить себя это использовать. Спасибо за идею — буду пробовать, если не запинаю более традиционными способами.
Re[3]: Не могу явно инстанцировать шаблон функции-члена
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Есть ли более надежные способы борьбы с этим, кроме вот такого извращения?
ЕМ>
ЕМ> return static_cast <ResType> (static_cast <ResType> (0) + a * b / 1000000);
ЕМ>
Это не защищает от промежуточного переполнения
Я про другое, вообще-то.
1) Тип результата всё равно указываешь при вызове, при этом из контекста знаешь, какая точность тут нужна. Зачем как-то параметризовать аргументы?
Типа имеешь два комплекта функций Short и Long и вперёд.
В Long сразу на входе просишь 64-битные данные, в Short в Debug-версии проверяешь переполнение (например сравниваешь с результатом Long-аналога)
2) Как происходит остальная параметризация я не понял. секунды и такты -- это разные типы или и то и то -- числа, а кто секунды, а кто такты определяется именем функции/аргумента?
3) Если это зачем-то надо, можно сделать параметром шаблона Long версию брать или Short.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот меня и вымораживает то, что вместо адекватных языковых средств управления приоритетами и доступностью шаблонных функций, идеологами C++ предлагаются извращения через метапрограммирование. По сути, это костыли, и выглядят уродливо, хотя и работают как-то. Очень трудно заставить себя это использовать. Спасибо за идею — буду пробовать, если не запинаю более традиционными способами.
Да ты просто не хочешь пользоваться тем, что предлагают в С++
Вот смотри, эта твоя MulAddDiv
Пишешь ШАБЛОН
template<typename T> T MulAddDiv( T a, T b, T c, T d)
{
return (a * b + c) / d;
}
И пишешь ДРУГОЙ шаблон
template<typename TRes> TRes MulAddDiv( int a, int b, int c, int d)
{
return static_cast<TRes>( тут вычисляем с использованием особенностей x86 )
}
Ну и потом тип результата определяется всё равно тем, что должно получиться, так что всё равно при вызове надо звать MulAddDiv<int> или MulAddDiv<long long> или ещё как там вам надо
Ну и так для всех исключений из общего варианта.
Если надо подавить автоматический вывод T в первом варианте, можно сделать промежуточный шаблон Ideal<T>::Type, например
Но ты же не хочешь так делать? Хотя я не понимаю почему.
p. s.
Ну и перед тем, как что-то делать, я бы ещё глянул а не делает ли всё см оптимизатор. Может достаточно просто верно типы параметров и результата задавть?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Не могу явно инстанцировать шаблон функции-члена
ЕМ>> return static_cast <ResType> (static_cast <ResType> (0) + a * b / 1000000);
ЕМ>>
E>Это не защищает от промежуточного переполнения
Защищает — если тип результата 64-разрядный, то и все выражение будет вычисляться в 64-разрядной сетке, даже если все параметры 32-разрядные.
E>1) Тип результата всё равно указываешь при вызове, при этом из контекста знаешь, какая точность тут нужна.
Кстати, я в упор не могу понять, почему язык запрещает перегружать функции только по типу результата, хотя возможностей для явного выбора нужного типа при вызове достаточно. Ссылаются на проблемы с манглингом, но и их можно избежать в статических/инлайновых вариантах. Как у них стремление к формальной строгости сочетается с раздолбайством в подходах?
E>Зачем как-то параметризовать аргументы? Типа имеешь два комплекта функций Short и Long и вперёд.
Так оно не работает. Если я определяю варианты с тремя параметрами (например, все short и все long), то компилятор утверждает, что он не может подобрать нужный вариант для какого-нибудь сочетания (short, long, short). А все потому, что он считает допустимым неявное преобразование long в short, и это еще один очевидный идиотизм, разумного оправдания которому я не знаю. Компилятор соглашается применять только варианты, в точности подходящие по типам к данному набору фактических параметров.
E>В Long сразу на входе просишь 64-битные данные, в Short в Debug-версии проверяешь переполнение (например сравниваешь с результатом Long-аналога)
Именно так я и хотел сделать.
E>2) секунды и такты -- это разные типы или и то и то -- числа
Это обычные числа (unsigned int или unsigned long).
Re[10]: Не могу явно инстанцировать шаблон функции-члена
Здравствуйте, Erop, Вы писали:
E>Пишешь ШАБЛОН [c] E>И пишешь ДРУГОЙ шаблон [c]
Все прекрасно работает, пока я эти шаблонные функции вызываю напрямую, имея возможность явно указать и тип результата (через параметр шаблона), и типы параметров. Ад и израиль начинаются тогда, когда я пытаюсь использовать хоть перегруженную, хоть шаблонную функцию в другой шаблонной функции, где любое уточнение сразу же приводит к резкому сужению диапазона возможных сочетаний параметров на входе и выходе. Например, "внешняя" шаблонная функция может вызывать MulAddDiv с двумя параметрами-членами класса, типы которых известны, и двумя собственными, типы которых неизвестны. А компилятор, из-за неестественно широких возможностей неявного преобразования типов, не может выбрать подходящий вариант, а языковых средств управления приоритетами не предлагает.
E> Ну и потом тип результата определяется всё равно тем, что должно получиться
Не только. Например, 32-разрядный результат из 32-разрядных параметров можно получить как оптимизированным вариантом MulAddDiv, так и приведением к 32 разрядам обычной арифметической формулы, которая может содержать хоть 64-, хоть 16-разрядные параметры. Вызывая MulAddDiv напрямую, я могу указать все это явно — оно будет, хоть и громоздко, но однозначно. А вот как мне заставить компилятор для любых сочетаний 32-разрядных беззнаковых параметров (например, UINT, ULONG, ULONG, UINT) всегда вызывать оптимизированную версию, неявно преобразуя UINT к ULONG, не применяя уродливых техник метапрограммирования — не понимаю.
E>Ну и перед тем, как что-то делать, я бы ещё глянул а не делает ли всё см оптимизатор.
В каждой новой версии компилятора гляжу — не делает. И вряд ли будет делать, ибо подобная оптимизация не гарантирует верных результатов и отсутствия переполнений при делении для всех возможных значений параметров. Но я-то учитываю допустимое подмножество, и использую оптимизацию только внутри него. Оптимизатор для частных случаев подгонять никто не станет.
Re: Не могу явно инстанцировать шаблон функции-члена
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, andyp, Вы писали:
A>>я бы ResultType и тип для промежуточных вычислений выбирал как-то так:
ЕМ>Я бы с удовольствием, но у меня много кода под виндовое ядро, там std [почти] нет, а выдирать и тащить фрагментами — то еще удовольствие. Ну и очень желательно сделать все средствами VC++ 15.00 (из VS 2008 и WDK 7).
Современный WDK умеет работать с <type_traits>: WDK и C++
Не "современный", а "самые последние" (года два назад сделали, или даже позже). Они уже несовместимы с моей VS 2008, а менять студию без крайней необходимости не хочу.
Re[3]: Не могу явно инстанцировать шаблон функции-члена
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, BigBoss, Вы писали:
BB>>Использовать неполную инстанциацию шаблона с дополнительным типом со значением по умолчанию.
ЕМ>Так и делал.
Вы безнадёжны! Один советует использовать несуществующую вещь, другой — говорит, что её использовал.
Re[4]: Не могу явно инстанцировать шаблон функции-члена
Здравствуйте, watchmaker, Вы писали:
W>Вы безнадёжны! Один советует использовать несуществующую вещь, другой — говорит, что её использовал.
Я нередко путаюсь в терминлологии. А делал я добавление к параметрам перегруженной функции неиспользуемого параметра, по которому шаблон другой функции выбирает нужные сочетания.
Re[5]: Не могу явно инстанцировать шаблон функции-члена
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я нередко путаюсь в терминлологии. А делал я добавление к параметрам перегруженной функции неиспользуемого параметра, по которому шаблон другой функции выбирает нужные сочетания.
ЕМ>Затем прямо в определении класса пытаюсь его инстанцировать:
Так не надо, можно в том же заголовочном файле, но после декларации класса
template <> short Class:: func <short, short , Fake = void> (short) {...};
Это неполная инстациация, Fake, хоть и имеет значение по умолчанию, по-прежнему неопределен. Однако компилятор увидев в коде func<short, short> догадается до func<short, short, void>, что и требовалось.
А еще проще можно сделать тоже самое в неанонимном namespace, там разрешена даже полная инстанциация. Опять-таки, вне декларации класса, но в том же заголовке.
Подробности разжеваны на stackoverflow и не по одному разу