Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.10.18 18:03
Оценка:
Хочу в классе иметь несколько вариантов одной и той же мелкой вычислительной (а потому инлайновой) функции. Создаю шаблон:

  template <typename ArgType, typename ResType>
  ResType func (ArgType Arg) { return ResType (Arg * i);   }


Затем прямо в определении класса пытаюсь его инстанцировать:

  template short func <short, short> (short);


На что MS VC++ версий от 13.10 до 15.00 выдает "error C2252: cannot explicitly instantiate template in current scope". В 19.10 сообщение поменялось на "error C2252: an explicit instantiation of a template can only occur at namespace scope".

В описании ошибки предлагается добавить "<>" после template, и заодно там явно указывается имя класса.

Вот такой пример успешно компилируется всеми имеющимися у меня версиями MS VC++, которые дружно оформляют все вызовы func, как внешние. То есть, фактически не срабатывают ни инстанциаци, ни инлайнинг.

  Скрытый текст
class Calc {

  int i;

  public:

  template <typename ArgType, typename ResType>
  ResType func (ArgType Arg) { return ResType (Arg * i);   }

  template <> short func <short, short> (short);
  template <> unsigned int func <unsigned int, unsigned int> (unsigned int);

};



int f (short s, unsigned int ui) {

  Calc c;

  short s2 = c.func <short, short> (s);

  unsigned int ui2 = c.func <unsigned int, unsigned int> (ui);

  return int (s2 + ui2);

}


int main () {

  return f (-31435, 8757849873);

}


Что там нужно сделать, чтобы нужные версии функции явно инстанциировались и проинлайнились в режиме оптимизации?
Отредактировано 09.10.2018 18:09 Евгений Музыченко . Предыдущая версия .
template function member explicit instantiation c2252
Re: Не могу явно инстанцировать шаблон функции-члена
От: rg45 СССР  
Дата: 09.10.18 18:42
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>На что MS VC++ версий от 13.10 до 15.00 выдает "error C2252: cannot explicitly instantiate template in current scope". В 19.10 сообщение поменялось на "error C2252: an explicit instantiation of a template can only occur at namespace scope".


Согласно стандару (п. 17.7.2/6), такая явная специализация должна выполняться в обрамляющем пространстве имен, о чем компилятор и говорит вполне ясно.

An explicit instantiation of a class, function template, or variable template specialization is placed in the namespace in which the template is defined. An explicit instantiation for a member of a class template is placed in the namespace where the enclosing class template is defined. An explicit instantiation for a member template is placed in the namespace where the enclosing class or class template is defined.


ЕМ>В описании ошибки предлагается добавить "<>" после template, и заодно там явно указывается имя класса.


Пардон за каламбур, но похоже, в опсании ошибки допущена ошибка — явную специализацию хотели сделать как положено, в пространстве имен (о чем намекает присутствие явной спецификации имени класса), но нечаянно загнали внутрь класса.

ЕМ>Вот такой пример успешно компилируется всеми имеющимися у меня версиями MS VC++...


Считай это ошибкой прошлого
--
Re: Не могу явно инстанцировать шаблон функции-члена
От: watchmaker  
Дата: 09.10.18 18:44
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Хочу в классе иметь несколько вариантов одной и той же мелкой вычислительной (а потому инлайновой) функции. Создаю шаблон:


ЕМ>
ЕМ>  template <typename ArgType, typename ResType>
ЕМ>  ResType func (ArgType Arg) { return ResType (Arg * i);   }
ЕМ>


ЕМ>Затем прямо в определении класса пытаюсь его инстанцировать:


Но зачем?!
Убери свои строки с "инстанциированием" из исходника — и всё будет работать как надо.

ЕМ>В описании ошибки предлагается добавить "<>" после template, и заодно там явно указывается имя класса.


Забавно :)
Добавление <> — это для описания специализации.
То есть, для ситуации, когда кто-то хотел сделать специализацию, но забыл написать <>, в справке говорят, что нужно написать <>.

ЕМ>Вот такой пример успешно компилируется всеми имеющимися у меня версиями MS VC++, которые дружно оформляют все вызовы func, как внешние. То есть, фактически не срабатывают ни инстанциаци, ни инлайнинг.


Ну в некоторой степени это даже логично: ты добавил <> и тем самым написал, что будет специализация. Но тело функции для специализации не предоставил. Разумеется компилятор тут ничего кроме внешнего вызова и не может сделать.

ЕМ>Что там нужно сделать, чтобы нужные версии функции явно инстанциировались и проинлайнились в режиме оптимизации?


Инстанциирование делается в namespace-scope:
class Calc { … };

template short Calc::func <short, short> (short z);


Но повторю: не надо это делать явно. Ну или объясняй зачем.
Отредактировано 09.10.2018 18:51 watchmaker . Предыдущая версия . Еще …
Отредактировано 09.10.2018 18:45 watchmaker . Предыдущая версия .
Re[2]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.10.18 18:49
Оценка:
Здравствуйте, rg45, Вы писали:

R>Согласно стандару (п. 17.7.2/6), такая явная специализация должна выполняться в обрамляющем пространстве имен


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

R>похоже, в опсании ошибки допущена ошибка


Похоже на то. Поэтому оно и сбило меня с толку.
Re[3]: Не могу явно инстанцировать шаблон функции-члена
От: rg45 СССР  
Дата: 09.10.18 18:52
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

R>>Согласно стандару (п. 17.7.2/6), такая явная специализация должна выполняться в обрамляющем пространстве имен


ЕМ>Я это подозревал, и пробовал выносить наружу, но там возникали какие-то другие ошибки.


С точки зрения стандарта валидной является любая из следующих форм:

template short A::func (short);
template short A::func<> (short);
template short A::func<short> (short);
template short A::func<short, short> (short);


Попробуй так и эдак, какая-нибудь да подойдет.

И еще, я бы на твоем месте поменял параметры шаблона местами. Посколько тип параметра выводится автоматически, а вот тип результата всегда придется указывать явно.
--
Re[2]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.10.18 19:04
Оценка:
Здравствуйте, watchmaker, Вы писали:

ЕМ>>Затем прямо в определении класса пытаюсь его инстанцировать:


W>Но зачем?!


В исходном варианте некоторых функций были принудительные приведения типов для обрезания ненужных старших частей 64-разрядных результатов, чтобы вернуть только значащую 32-разрядную часть, и избежать лишних расходов на 32-разрядных платформах. Поэтому хотелось инстанцировать только безопасные сочетания типов. Сейчас уже кажется, что правильнее будет явно указывать типы при вызовах таких функций.

W>Добавление <> — это для описания специализации.


Стыдно сказать, но я до сих пор не до конца понимаю, чем отличается специализация шаблона от инстанцирования. Я на C++ делаю в основном низкоуровневный код, поэтому никогда предметно не разбирался с конструкциями, способными давать трудно контролируемый рост кода. Поэтому из шаблонов применяю в первую очередь шаблоны классов, экземпляры которых сами не плодятся.
Re[4]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.10.18 19:10
Оценка:
Здравствуйте, rg45, Вы писали:

R>я бы на твоем месте поменял параметры шаблона местами.


Угу, я так и сделал после того, как убрал инстанцирование и стал явно указывать тип результата при вызове.
Re[3]: Не могу явно инстанцировать шаблон функции-члена
От: watchmaker  
Дата: 09.10.18 19:15
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Поэтому хотелось инстанцировать только безопасные сочетания типов.

Иначе говоря, ты вручную явно инстанциируешь все безопасные комбинации, а компилятору оставишь работу по неявному инстанциированию всех остальных вариантов? Отличный план!
Ну то есть инстанциирование — это про другое.

Если хочешь запретить некие комбинации типов, то используй enable_if или просто static_assert с условием напиши.
Если хочешь для некоторых комбинаций типов сделать специальную логику обработки (не по шаблону), то используй специализацию этих типов для них (даже слова однокоренные!).
Re[4]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.10.18 20:44
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Иначе говоря, ты вручную явно инстанциируешь все безопасные комбинации, а компилятору оставишь работу по неявному инстанциированию всех остальных вариантов?


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

W>Если хочешь запретить некие комбинации типов, то используй enable_if или просто static_assert с условием напиши.


Я в коде для ядра не использую std, чтоб не возникало неожиданных зависимостей. Попробую выдрать из библиотеки.
Re[5]: Не могу явно инстанцировать шаблон функции-члена
От: rg45 СССР  
Дата: 09.10.18 20:53
Оценка: +4
Здравствуйте, Евгений Музыченко, Вы писали:

W>>Иначе говоря, ты вручную явно инстанциируешь все безопасные комбинации, а компилятору оставишь работу по неявному инстанциированию всех остальных вариантов?


ЕМ>Насколько я понимаю, так у него будет меньше шансов автоматически выбрать опасный вариант.


Нет. Ты меняешь время и место инстанцирования, только и всего. На выбор специализаций/перегрузок это никак не влияет.
--
Re: Не могу явно инстанцировать шаблон функции-члена
От: Erop Россия  
Дата: 11.10.18 04:09
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Затем прямо в определении класса пытаюсь его инстанцировать:

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

С другой стороны, тип результата всё равно явно надо указывать, при вызове, так что не ясно чем шаблон плох. Зачем с ним бороться и пытаться какие-то комбинации запретить?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 11.10.18 07:18
Оценка:
Здравствуйте, Erop, Вы писали:

E>А зачем тебе вообще шблон в этом месте? Просто перегруженный метод напиши, и не парься.


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

Можно, конечно, вычислять все в 64-разрядной точности, а затем обрезать, если нужно, но на 32-разрядных платформах это слишком расточительно в отношении небольших объемов/длительностей, которые отлично вычисляются в 32 разрядах.

E>Зачем с ним бороться и пытаться какие-то комбинации запретить?


Да просто для вящей безопасности, чтобы не обрезать лишнего.

Кстати, тут еще одна проблема — при повышении разрядности от параметров к результату хочется как-то обеспечить автоматическое повышение точности. Например, в шаблоне

template <typename ResType, typename ArgType> ResType MulDiv (ArgType a, ArgType b) {
  return static_cast <ResType> (a * b / 1000000);
}


легко можно вызвать промежуточное переполнение и потерю старших разрядов, если параметры 32-разрядные, а результат — 64-разрядный.

Есть ли более надежные способы борьбы с этим, кроме вот такого извращения?

  return static_cast <ResType> (static_cast <ResType> (0) + a * b / 1000000);
Отредактировано 11.10.2018 7:19 Евгений Музыченко (исправлена ошибка) . Предыдущая версия .
Re[3]: Не могу явно инстанцировать шаблон функции-члена
От: andyp  
Дата: 11.10.18 08:31
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Есть ли более надежные способы борьбы с этим, кроме вот такого извращения?


ЕМ>
ЕМ>  return static_cast <ResType> (static_cast <ResType> (0) + a * b / 1000000);
ЕМ>


Для начала, я бы ResultType и тип для промежуточных вычислений выбирал как-то так:


template<typename T, typename Enabler = void> struct ResultTypeSelector {typedef T type;};

template<typename T>
struct ResultTypeSelector <T, typename std::enable_if_t<std::is_same<T,int>::value>>
{
//тут описываешь свои правила
    typedef int64_t type;
    typedef int64_t IntermedType;    
};

//и т.п. 


template <typename ArgType> typename ResultTypeSelector<ArgType>::type MulDiv (ArgType a, ArgType b) {
    using ReturnType = ResultTypeSelector<ArgType>::type;
    using IntermedType = ResultTypeSelector<ArgType>::IntermedType;
    return ReturnType((IntermedType(a) * IntermedType(b)/10000));
}
Отредактировано 11.10.2018 8:33 andyp . Предыдущая версия . Еще …
Отредактировано 11.10.2018 8:32 andyp . Предыдущая версия .
Re[3]: Не могу явно инстанцировать шаблон функции-члена
От: rg45 СССР  
Дата: 11.10.18 10:36
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Кстати, тут еще одна проблема — при повышении разрядности от параметров к результату хочется как-то обеспечить автоматическое повышение точности. Например, в шаблоне


ЕМ>
ЕМ>template <typename ResType, typename ArgType> ResType MulDiv (ArgType a, ArgType b) {
ЕМ>  return static_cast <ResType> (a * b / 1000000);
ЕМ>}
ЕМ>


ЕМ>легко можно вызвать промежуточное переполнение и потерю старших разрядов, если параметры 32-разрядные, а результат — 64-разрядный.


ЕМ>Есть ли более надежные способы борьбы с этим, кроме вот такого извращения?


template <typename T, typename U>
using ProductType = decltype(std::declval<T>() * std::declval<U>());

template <typename T, typename U>
ProductType<T, U> MulDiv(const T& t, const U& u) { return t * u / 1000000; }
--
Re[4]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 11.10.18 13:43
Оценка:
Здравствуйте, andyp, Вы писали:

A>я бы ResultType и тип для промежуточных вычислений выбирал как-то так:


Я бы с удовольствием, но у меня много кода под виндовое ядро, там std [почти] нет, а выдирать и тащить фрагментами — то еще удовольствие. Ну и очень желательно сделать все средствами VC++ 15.00 (из VS 2008 и WDK 7).
Re[3]: Не могу явно инстанцировать шаблон функции-члена
От: watchmaker  
Дата: 11.10.18 14:06
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>Например, в шаблоне

ЕМ>
ЕМ>template <typename ResType, typename ArgType> ResType MulDiv (ArgType a, ArgType b) {
ЕМ>  return static_cast <ResType> (a * b / 1000000);
ЕМ>}

ЕМ>легко можно вызвать промежуточное переполнение и потерю старших разрядов, если параметры 32-разрядные, а результат — 64-разрядный.
ЕМ>Есть ли более надежные способы борьбы с этим, кроме вот такого извращения?
ЕМ>  return static_cast <ResType> (static_cast <ResType> (0) + a * b / 1000000);


Надеюсь, что этот пример был взят не из реального кода, а просто невнимательно написан прямо на форуме.
Ибо такая запись не только выглядит некрасиво, но ещё и оказывается семантически эквивалентной первому варианту. То есть тоже будет страдать от 32-х битного переполнения. Ведь хотя паттерн static_cast<ResType>(0) действительно существует, но в данном коде он использован неправильно.
Re[5]: Не могу явно инстанцировать шаблон функции-члена
От: andyp  
Дата: 11.10.18 14:12
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Я бы с удовольствием, но у меня много кода под виндовое ядро, там std [почти] нет, а выдирать и тащить фрагментами — то еще удовольствие. Ну и очень желательно сделать все средствами VC++ 15.00 (из VS 2008 и WDK 7).


Я про ядро и возможности VS2008 мало знаю (.

Сухая идея — избавиться от второго параметра шаблона функции выводя тип результата из типа аргумента функции, используя трейты для нужных типов. Всё, что использовал, живет в cstdint и type_traits и может быть использовано без С++11, если использовать enable_if<...>::type вместо enable_if_t и typedef вместо using.


Если совсем уж без стандартных заголовков, то примерно вот велосипедные is_same и enable_if:


template<typename First, typename Second> is_same{static const bool value = false;};
temaple<typename T> is_same<T, T>{static const bool value = true;}


template<bool Key, class T = void> struct enable_if{};
template<class T> struct enable_if<true, T> {typedef T type;};
Re[4]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 11.10.18 14:15
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>
ЕМ>>  return static_cast <ResType> (static_cast <ResType> (0) + a * b / 1000000);
W>


W>Надеюсь, что этот пример был взят не из реального кода, а просто невнимательно написан прямо на форуме.


Угу, в реальном коде есть нужные скобки.
Re[5]: Не могу явно инстанцировать шаблон функции-члена
От: Conr Россия  
Дата: 11.10.18 14:36
Оценка: 6 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

W>>Если хочешь запретить некие комбинации типов, то используй enable_if или просто static_assert с условием напиши.

ЕМ>Я в коде для ядра не использую std, чтоб не возникало неожиданных зависимостей. Попробую выдрать из библиотеки.
В свежей студии (VS 2017 15.8) можно уже спокойно использовать <type_traits>, они специально для драйверистов его почистили:
https://blogs.msdn.microsoft.com/vcblog/2018/09/18/stl-features-and-fixes-in-vs-2017-15-8/
Re[6]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 11.10.18 15:23
Оценка:
Здравствуйте, andyp, Вы писали:

A>Я про ядро и возможности VS2008 мало знаю (.


Использование стандартных шаблонов само по себе никак не мешает компиляции под ядро, ибо все разруливается компилятором, но включение type_traits тянет за собой заголовки, несовместимые с заголовками WDK/DDK. Поэтому только выдирать, или определять собственное.

A>Сухая идея — избавиться от второго параметра шаблона функции выводя тип результата из типа аргумента функции, используя трейты для нужных типов.


Мне кажется, что для функций с тремя-четырьмя параметрами это будет неимоверно громоздко. Например, у меня есть функция MulAddDiv, вычисляющая выражение "(a * b + c) / d" с использованием особенностей x86 (команды перемножения 32-разрядных в 64-разрядное, и обратный вариант деления). Соответственно, для 32-разрядных типов используется эта реализация, а все остальные варианты, имеющие хотя бы один 64-разрядный параметр, реализуются "втупую".

Но из-за ублюдочного подхода C++, не позволяющего явно указать приоритеты неявных преобразований, мне приходится явно определять все возможные 32-разрядные варианты (int/long, signed/unsigned). И это я еще не использую эти функции с char и short. Остальные варианты можно определить шаблонами, но и тут элементарная, по сути, задача превращается в танцы с бубном и сотню строк кода.

A>Если совсем уж без стандартных заголовков, то примерно вот велосипедные is_same и enable_if:


Спасибо, попробую с ними.
Re[6]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 11.10.18 15:24
Оценка:
Здравствуйте, Conr, Вы писали:

C>В свежей студии (VS 2017 15.8) можно уже спокойно использовать <type_traits>, они специально для драйверистов его почистили


Читал, но переходить на свежие студии (как и на Win10) буду только после того, как на VS 2008 и Win10 станет совсем невмоготу. Нечеловеческие они.
Re[7]: Не могу явно инстанцировать шаблон функции-члена
От: andyp  
Дата: 11.10.18 21:31
Оценка: 6 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Мне кажется, что для функций с тремя-четырьмя параметрами это будет неимоверно громоздко. Например, у меня есть функция 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>)

Для двух входных аргументов как-то так
template<typename T1, typename T2, typename Enabler = void> struct ResultTypeSelector {typedef T type;};

template<typename T1, typename T2>
struct ResultTypeSelector <T, typename std::enable_if_t<

(std::is_intergal<T1>::value) && (std::is_intergal<T2>::value) &&
(std::numeric_limits<T1>::digits <= 32) &&
(std::numeric_limits<T2>::digits <= 32) 

>
{
//тут описываешь свои правила
    typedef int32_t ResType; //тип результата
    typedef int32_t IntermedType; //тип промежуточных данных   
};

template<typename T1, typename T2>
struct ResultTypeSelector <T, typename std::enable_if_t<

(std::is_intergal<T1>::value) && (std::is_intergal<T2>::value) &&
((std::numeric_limits<T1>::digits > 32) ||
(std::numeric_limits<T2>::digits  > 32)) 

>
{
//тут описываешь свои правила
    typedef int64_t ResType; //тип результата
    typedef int64_t IntermedType; //тип промежуточных данных   
};


Перед вычислениями внутри функции все аргументы приводишь к IntermedType.
Re[8]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.10.18 07:32
Оценка:
Здравствуйте, andyp, Вы писали:

A>т.е. иметь столько параметров шаблона, сколько и аргументов.


A>Предложенный селектор можно специализировать для аргументов-целых чисел, разрядностью меньше чем 32 и чисел разрядностью больше 32. Но это будет больше писанины и использования стандартной библиотеки (потребуется is_integral из type_traits и всякое из <limits>)


Вот меня и вымораживает то, что вместо адекватных языковых средств управления приоритетами и доступностью шаблонных функций, идеологами C++ предлагаются извращения через метапрограммирование. По сути, это костыли, и выглядят уродливо, хотя и работают как-то. Очень трудно заставить себя это использовать. Спасибо за идею — буду пробовать, если не запинаю более традиционными способами.
Re[3]: Не могу явно инстанцировать шаблон функции-члена
От: Erop Россия  
Дата: 12.10.18 12:16
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Есть ли более надежные способы борьбы с этим, кроме вот такого извращения?


ЕМ>
ЕМ>  return static_cast <ResType> (static_cast <ResType> (0) + a * b / 1000000);
ЕМ>



Это не защищает от промежуточного переполнения

Я про другое, вообще-то.

1) Тип результата всё равно указываешь при вызове, при этом из контекста знаешь, какая точность тут нужна. Зачем как-то параметризовать аргументы?
Типа имеешь два комплекта функций Short и Long и вперёд.
В Long сразу на входе просишь 64-битные данные, в Short в Debug-версии проверяешь переполнение (например сравниваешь с результатом Long-аналога)

2) Как происходит остальная параметризация я не понял. секунды и такты -- это разные типы или и то и то -- числа, а кто секунды, а кто такты определяется именем функции/аргумента?

3) Если это зачем-то надо, можно сделать параметром шаблона Long версию брать или Short.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 12.10.2018 12:33 Erop . Предыдущая версия .
Re[9]: Не могу явно инстанцировать шаблон функции-члена
От: Erop Россия  
Дата: 12.10.18 12:33
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Вот меня и вымораживает то, что вместо адекватных языковых средств управления приоритетами и доступностью шаблонных функций, идеологами 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]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.10.18 13:02
Оценка:
Здравствуйте, Erop, Вы писали:

ЕМ>>
ЕМ>>  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]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.10.18 13:26
Оценка:
Здравствуйте, Erop, Вы писали:

E>Пишешь ШАБЛОН [c]

E>И пишешь ДРУГОЙ шаблон [c]

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

E> Ну и потом тип результата определяется всё равно тем, что должно получиться


Не только. Например, 32-разрядный результат из 32-разрядных параметров можно получить как оптимизированным вариантом MulAddDiv, так и приведением к 32 разрядам обычной арифметической формулы, которая может содержать хоть 64-, хоть 16-разрядные параметры. Вызывая MulAddDiv напрямую, я могу указать все это явно — оно будет, хоть и громоздко, но однозначно. А вот как мне заставить компилятор для любых сочетаний 32-разрядных беззнаковых параметров (например, UINT, ULONG, ULONG, UINT) всегда вызывать оптимизированную версию, неявно преобразуя UINT к ULONG, не применяя уродливых техник метапрограммирования — не понимаю.

E>Ну и перед тем, как что-то делать, я бы ещё глянул а не делает ли всё см оптимизатор.


В каждой новой версии компилятора гляжу — не делает. И вряд ли будет делать, ибо подобная оптимизация не гарантирует верных результатов и отсутствия переполнений при делении для всех возможных значений параметров. Но я-то учитываю допустимое подмножество, и использую оптимизацию только внутри него. Оптимизатор для частных случаев подгонять никто не станет.
Re: Не могу явно инстанцировать шаблон функции-члена
От: BigBoss  
Дата: 28.10.18 03:19
Оценка: -1
ЕМ>Что там нужно сделать, чтобы нужные версии функции явно инстанциировались и проинлайнились в режиме оптимизации?

Использовать неполную инстанциацию шаблона с дополнительным типом со значением по умолчанию.
Выглядит коряво, но соответствует стандарту и работает.
Re[5]: Не могу явно инстанцировать шаблон функции-члена
От: _NN_ www.nemerleweb.com
Дата: 28.10.18 12:47
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, andyp, Вы писали:


A>>я бы ResultType и тип для промежуточных вычислений выбирал как-то так:


ЕМ>Я бы с удовольствием, но у меня много кода под виндовое ядро, там std [почти] нет, а выдирать и тащить фрагментами — то еще удовольствие. Ну и очень желательно сделать все средствами VC++ 15.00 (из VS 2008 и WDK 7).


Современный WDK умеет работать с <type_traits>: WDK и C++
Автор: EreTIk
Дата: 03.10.18
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.10.18 01:54
Оценка: -1
Здравствуйте, BigBoss, Вы писали:

BB>Использовать неполную инстанциацию шаблона с дополнительным типом со значением по умолчанию.


Так и делал.
Re[6]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.10.18 01:57
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Современный WDK умеет работать с <type_traits>: WDK и C++
Автор: EreTIk
Дата: 03.10.18


Не "современный", а "самые последние" (года два назад сделали, или даже позже). Они уже несовместимы с моей VS 2008, а менять студию без крайней необходимости не хочу.
Re[3]: Не могу явно инстанцировать шаблон функции-члена
От: watchmaker  
Дата: 29.10.18 06:01
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, BigBoss, Вы писали:


BB>>Использовать неполную инстанциацию шаблона с дополнительным типом со значением по умолчанию.


ЕМ>Так и делал.


Вы безнадёжны! Один советует использовать несуществующую вещь, другой — говорит, что её использовал.
Re[4]: Не могу явно инстанцировать шаблон функции-члена
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.10.18 06:09
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Вы безнадёжны! Один советует использовать несуществующую вещь, другой — говорит, что её использовал.


Я нередко путаюсь в терминлологии. А делал я добавление к параметрам перегруженной функции неиспользуемого параметра, по которому шаблон другой функции выбирает нужные сочетания.
Re[5]: Не могу явно инстанцировать шаблон функции-члена
От: BigBoss  
Дата: 31.10.18 00:16
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Я нередко путаюсь в терминлологии. А делал я добавление к параметрам перегруженной функции неиспользуемого параметра, по которому шаблон другой функции выбирает нужные сочетания.


Я тоже Ну чтоб не путаться:

template <typename ArgType, typename ResType , typename Fake>
ResType func (ArgType Arg) { return ResType (Arg * i); }


ЕМ>Затем прямо в определении класса пытаюсь его инстанцировать:


Так не надо, можно в том же заголовочном файле, но после декларации класса

template <> short Class:: func <short, short , Fake = void> (short) {...};

Это неполная инстациация, Fake, хоть и имеет значение по умолчанию, по-прежнему неопределен. Однако компилятор увидев в коде func<short, short> догадается до func<short, short, void>, что и требовалось.

А еще проще можно сделать тоже самое в неанонимном namespace, там разрешена даже полная инстанциация. Опять-таки, вне декларации класса, но в том же заголовке.

Подробности разжеваны на stackoverflow и не по одному разу
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.