Может ли С++ 17 вывести шаблоны шаблонов шаблонов `auto` не-типа` template` с явными параметрами не-типа?
Рассмотрим этот пример (также доступный в wandbox):
template <template <auto> class>
void test() { }
template <int>
struct X { };
Попытка создания экземпляра test<X>()
на clang++
4.0 (trunk) приводит к ошибке компиляции:
error: no matching function for call to 'test'
test<X>();
^~~~~~~
note: candidate template ignored:
invalid explicitly-specified argument for 1st template parameter
void test() { }
Мое первоначальное предположение/интуиция заключалось в том, что test
можно использовать для соответствия любому template
, имеющему непиковый параметр.
Однако, следующий фрагмент кода успешно компилируется:
template <template <auto> class>
void test() { }
// vvvv
template <auto>
struct X { };
Это предназначено? Не удалось найти ничего убедительного в P0127R2.
Ответы
Ответ 1
Это определенно предназначено. Параметры шаблона шаблона могут соответствовать шаблонам, которые принимают одни и те же аргументы. Это:
template <template <auto> class>
void test() { }
может быть создан только с шаблоном класса, который может принимать любой тип непигового параметра. Но это:
template <int>
struct X { };
не является таким шаблоном класса. X
может быть создан только с помощью int
. Это просто не соответствует спецификации шаблона шаблона, следовательно, ошибка. Что делать, если test
хотел создать экземпляр своего шаблона класса с типом указателя? Или указатель на функцию или указатель на член? Это было бы невозможно.
Вторая попытка с template <auto> struct X { };
соответствует параметру шаблона-шаблона, следовательно, корректна. Также обратите внимание, что обратное, имеющее test
принимает параметр template <int> class
, а передача в template <auto> struct X { };
также хорошо сформирована, поскольку аргумент является более общим, чем параметр.
Соответствующая формулировка находится в [temp.arg.template]:
Аргумент шаблона соответствует шаблону-шаблону шаблона P
, когда каждый из параметров шаблона в шаблоне-параметре-списке шаблонов-аргументов соответствует шаблону соответствующего шаблона или шаблону алиаса A
соответствует соответствующий параметр шаблона в списке параметров шаблона P
. Два параметра шаблона совпадают, если они имеют один и тот же вид (тип, не тип, шаблон), для шаблонов-шаблонов непигового типа, их типы эквивалент (14.5.6.1), а для шаблонных шаблонов-параметров каждый из их соответствующих параметров шаблона соответствует рекурсивно.
Примечание: формулировка эквивалентности принимает случай auto
- auto
и отклоняет случай auto
- int
, но также, похоже, отклоняет случай int
- auto
(на основе моего чтения), Я попытаюсь получить разъяснения.
Ответ 2
В дополнение к ответу Барри, в котором мне было любопытно, вот четыре возможные комбинации и результаты с использованием Clang 4.0 (SVN), см. также в wandbox:
template <bool> struct obj_bool { }; // object taking a value of boolean type
template <auto> struct obj_auto { }; // object taking a value of deduced type
// ^^^^^^ Note: this is a template value argument (non-type template argument)
template <template <auto> typename> void fn_auto() { }
template <template <bool> typename> void fn_bool() { }
// ^^^^^^^^^^^^^^^^^^^^^^^^ Note: this is a template type argument
// ^^^^^^ taking a template value argument
int main() {
fn_bool<obj_bool>(); // #1 bool->bool OK (exact match)
fn_auto<obj_auto>(); // #2 auto->auto OK (exact match)
fn_bool<obj_auto>(); // #3 bool->auto OK (sub-set)
//fn_auto<obj_bool>(); // #4 auto->bool Error: no matching function.
}
Из этого, # 1 и # 2, очевидно, являются точными совпадениями и работают как ожидалось. # 3 будет ссылаться на реализацию bool на шаблоне, который может обрабатывать не только bool, но и все типы, тогда как # 4 будет пытаться вызвать определение, ожидающее обобщенного объекта (авто) с объектом, предоставляющим только подмножество (bool) возможностей.
Шаблонная функция fn_auto
promises возможные экземпляры для шаблонов, принимающих любой тип значения (авто). Таким образом, предоставление этого только подмножества возможностей (bool) нарушает это обещание.
Хотя это и не сразу очевидно, ограничение имеет смысл. И извините за то, что моя формулировка не соответствует стандарту С++.