Шаблон С++: не может соответствовать последнему шаблону в шаблоне вариационного класса

Я изучаю вариативный шаблон С++ 11 и создал структуру шаблона для вычисления максимального числа заданного списка и пробовал:

#include <iostream>
#include <type_traits>

template <int a, int b, int... cs>
struct max: std::integral_constant<int, (a>b? max<a, cs...>::value: max<b, cs...>::value)> {};
template <int a, int b>
struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value: max<b>::value)> {};
template <int a>
struct max<a>: std::integral_constant<int, a> {};

int main() {
  std::cout << max<2,1,5,7>::value << std::endl;
  return 0;
}

но g++ жалуется:

test.cc:7:58: error: wrong number of template arguments (1, should be at least 2)
 struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value : max<b>::value)> {};

test.cc:9:13: error: wrong number of template arguments (1, should be at least 2)
 struct max<a>: std::integral_constant<int, a> {};

Я могу запустить его, добавив впереди простое объявление:

template <int...>
struct max;

и измените первый шаблон выше на:

template <int a, int b, int... cs>
struct max<a, b, cs...>: ...

Я упомянул cppreference: https://en.cppreference.com/w/cpp/language/partial_specialization#Partial_ordering, но я не могу найти никакого полезного объяснения для моего случая.

Проблема может исходить от последнего шаблона (max<a>) только с одним параметром шаблона, который не является специализированной версией основного.

Итак, мой вопрос:

Почему max<a> нельзя сопоставить? Существуют ли какие-либо правила или стандарты, касающиеся этого?

=================================================================

Хорошо, я нашел стандарты C++ (документ № N4659), в которых говорится:

[Примечание. Частичные специализации шаблонов классов можно найти, просматривая шаблон основного класса и затем рассматривая все частичные специализации этого шаблона. Если использование-объявления именует шаблон класса, частичные специализации, введенные после использования-объявления, фактически видимы, поскольку первичный шаблон виден (17.5.5). — примечание в конце]

Так что я думаю, что любой частично специализированный шаблон, который не отличается от базового/первичного, считается ошибкой, хотя иногда мы можем генерировать некоторые неспециализированные формы выражения из обычных.


person bigtit    schedule 06.06.2018    source источник


Ответы (3)


Когда вы определяете шаблон класса как:

template <int a, int b, int... cs> struct max { ... };

Ниже приведена действующая специализация.

template <int a, int b> struct max<a, b> { ... };

Однако следующее не так.

template <int a> struct max<a> { ... };

поскольку для шаблона базового класса требуется как минимум два параметра шаблона.

person R Sahu    schedule 06.06.2018
comment
Так требует ли стандарт, чтобы следующий шаблон частичной спецификации был специализированной версией основного? - person bigtit; 06.06.2018
comment
@bigtit, я не понял тебя. Пожалуйста, дополните. - person R Sahu; 06.06.2018
comment
вы сказали since the base class template requires at least two template parameters., поэтому я предполагаю, что стандарт С++ заставляет все шаблоны после базового быть его специализированной версией, так как в этом случае max<a> не является более специализированной версией базового шаблона? - person bigtit; 06.06.2018

Не ответ, но почему бы и просто...

template <int a, int... bs>
struct max : std::integral_constant<int,
   (a > max<bs...>::value ? a : max<bs...>::value)> {};

template <int a>
struct max<a> : std::integral_constant<int, a> {};

...?

person Daniel Langr    schedule 06.06.2018
comment
почему бы тебе не сделать это ответом? Это не отвечает на вопрос буквально, но я думаю, это то, что на самом деле было после ОП. - person 463035818_is_not_a_number; 06.06.2018
comment
@ user463035818 Я не уверен в этом, так как OP запросил правила. Он даже знал, как заставить свое решение работать, добавив еще одну версию основного шаблона. - person Daniel Langr; 06.06.2018
comment
о, ты прав. Я неправильно понял вопрос, мне уже было интересно, почему в верхних ответах не упоминается, как это исправить;) - person 463035818_is_not_a_number; 06.06.2018

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

Ваш базовый шаблон должен соответствовать любому количеству аргументов и не иметь реализации (поскольку max<>::value не имеет смысла) и иметь один аргумент с переменным числом аргументов, а все остальные ваши классы будут его специализацией.

#include <iostream>
#include <type_traits>

template<int... cs>
struct max;

template <int a, int b, int... cs>
struct max<a, b, cs...>: std::integral_constant<int, (a>b? max<a, cs...>::value: max<b, cs...>::value)> {};
template <int a, int b>
struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value: max<b>::value)> {};
template <int a>
struct max<a>: std::integral_constant<int, a> {};

int main() {
  std::cout << max<2,1,5,7>::value << std::endl;
  return 0;
}
person Frank    schedule 06.06.2018
comment
На самом деле я пробовал другие записи с первичным шаблоном, имеющим реализации, и они работали нормально. Итак, я предполагаю, что вы имеете в виду «должен» здесь соглашение? - person bigtit; 06.06.2018
comment
@bigint, О, да, первичный шаблон может иметь реализацию. Просто в вашем случае max<>::value не имеет никакого смысла, поэтому вы должны оставить его неопределенным. Я изменил ответ, чтобы уточнить. - person Frank; 06.06.2018
comment
@Frank Можно утверждать, что max<>::value должно быть std::numeric_limits<int>::min(). В противном случае для базового шаблона должен требоваться хотя бы один аргумент шаблона. - person Deduplicator; 07.06.2018