Почему имена в шаблонах необязательны?

104
12 ноября 2019, 18:40

Смотрю описание шаблонов и заметил, что имена параметров везде помечены как необязательные, но ведь если имя отсутствует, то параметр внутри функции я использовать не смогу. Получается, что я могу объявить и вызвать такую функцию (https://ideone.com/VVicO8):

template <int> void f() {}

Но все версии этой функции будут одинаковы между собой - тогда зачем мне вообще параметр шаблона? Есть ли реальная пользя от возможности не указывать имя и создавать нечто подобное? Зачем вообще эта возможность заложена в стандарт?

Answer 1

Тема неиспользуемых аргументов в шаблонах классов уже поднималась: шаблонный класс, не использующий аргумент шаблона

В вашем конкретном примере - шаблон функции - использование фиктивного неименованного параметра может служить какой-то специальной внутренней более-менее экзотической технической цели.

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

assert(&f<1> != &f<2>);  
Answer 2

Не понимаю, почему вы решили, что все версии функции будут одинаковы. Отсутствие имени всего лишь означает, что параметр не используется, но это вовсе не значит, что f<7> это та же самая функция, что и f<5>, например. В частности можно сделать специализацию, которая будет делать что-то особенное, исходя из значения шаблонного аргумента:

#include <iostream>
template <int> 
void f() {}
template <> 
void f<7>() {
    std::cout << "seven\n";
}
int main()
{
  f<7>();
  return 0;
}
Answer 3

Немного перефразирую вопрос: Имеется ли смысл иметь в шаблоне параметр, который в этом шаблоне затем никак не используется? (Потому что опускать имя - это потеря семантики.)

Для этого есть масса сценариев:

  1. Параметр просто используется для тегирования чтобы можно было получать разные классы просто используя разные специализации этого шаблона. Например strong typedef template <typename x_Tag, typename x_Type> class t_StrongTypedef (x_Tag никак не используется, код от x_Tag не зависит, параметр задается пользователем)
  2. Банальная специализация для разных параметров. Например SIMD вариант для параметров int x_group_size 2/4/8. (x_group_size никак не используется, но код от x_group_size зависит, параметр задается пользователем)
  3. Использование как фиктивного параметра для SFINAE typename x_Enabled = ::std::enable_if_t< (x_Enabled никак не используется (и как раз часто опускается), код от x_Enabled не зависит, параметр может принимать только значение void и никогда не задается пользователем)
  4. Использование как фиктивного параметра для класса чтобы можно было определять статические поля этого класса в заголовочном файле не вызывая ошибок линковки typename x_Unused = void. (x_Unused никак не используется, код от x_Unused не зависит, параметр может принимать только значение void и никогда не задается пользователем)
READ ALSO
Сравнение двух строк, одна с пробелом

Сравнение двух строк, одна с пробелом

У меня есть функция поиска, но при сравнивании строки с помощью этой функции, strcmp(mas[ii]street,pt), и тут возникла проблема, строка которую ввожу,...

138
Адаптивность на форме Qt Creator

Адаптивность на форме Qt Creator

Такой вопрос, я добавляю динамически на форму следующие компоненты:

149
strict aliasing и char*

strict aliasing и char*

Пытаюсь понять, в какой мере strict aliasing rule не касается char

136
__attribute__((__packed__))

__attribute__((__packed__))

Не совсем понимаю, что происходит при упаковке, например, структур

158