Ответ 1
Это ошибка в предложении. Ограниченный шаблонный шаблонный параметр должен принимать аргументы с более слабыми ограничениями.
N3580 описывает следующий сценарий:
template<Object T, template<Object> Cont>
struct stack {
Cont<T> container;
};
template<Object>
struct my_vector;
template<Regular>
struct my_list;
template<typename>
struct my_magic;
Здесь Regular
является уточнением Object
; т.е. каждый Regular
является
Object
, но не каждый Object
является Regular
.
Я бы ожидал, что система типов будет таковой, что для stack<X, Y>
X
должен быть Object
, а Y
должен быть реалистичным с Object
. Эта
будет означать, что stack<int, my_vector>
и stack<int, my_magic>
действительны,
а stack<int, my_list>
- нет. Как и в случае с нормальными функциями:
struct Base {};
struct Derived : Base {};
void foo(Base* p, function<void(Base*)> fun) {
fun(p);
}
template<typename T>
void bar(T*);
Я бы ожидал, что если p
является Base*
, то foo(p, bar<Base>)
и foo(p,
bar<void>)
действительны, а foo(p, bar<Derived>)
- нет; в конце концов,
Base*
имеет неявное преобразование в void*
, но не в Derived*
.
Однако в случае шаблонов ситуация противоположная. Только
stack<int, my_vector>
и stack<int, my_list>
разрешены, а stack<int,
my_magic>
запрещено. Почему это? my_magic
работает отлично с любым типом,
а my_list
может выйти из строя в зависимости от того, какой объект я ему даю. Более того, я могу
тривиально сделать my_magic
работать только с объектами:
template<Object T>
struct my_restricted_magic : my_magic<T> {};
Теперь my_restricted_magic
можно использовать с stack
. С другой стороны, есть
нет простого способа сделать my_list
, который принимает любой тип, но это точно
что позволяет передать его как параметр шаблона шаблона.
Я неверно истолковываю цель ограничений для параметра шаблона шаблона параметры?
Это ошибка в предложении. Ограниченный шаблонный шаблонный параметр должен принимать аргументы с более слабыми ограничениями.
Это гипотеза, но это похоже на вероятное объяснение:
Предоставление более конкретного шаблона, а не более общего, - это способ, которым в настоящее время действуют правила в отношении параметров шаблона шаблона. Вы можете передать шаблон однотипного параметра, где ожидается переменная:
template<template<typename...> class> struct Foo {};
template<typename> Bar {};
Foo<Bar>(); // legal
Но не наоборот:
template<template<typename> class> struct Foo {};
template<typename...> Bar {};
Foo<Bar>(); // error, argument/parameter mismatch.
Фразы, возникшие в N2555, где было предложено разрешить такой код:
template<typename>
struct Foo;
template<template<typename...> class Fun, template... Args>
struct Foo<Fun<Args...>> {};
Foo<std::pair<int, double>>();
В принципе, вместо template<typename...> class
, являющегося гарантией для пользователя, это все, что нужно, чтобы пользователь должен был дать разумные аргументы. Учитывая это использование, связанное с специализациями, это кажется разумным.
Это не объясняет, почему использование более общего шаблона не допускается, но изменение фраз в N3580 сделало бы два правила составленными довольно неинтуитивными.
Ссылка на предложение: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf