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
, который принимает любой тип, но это точно
что позволяет передать его как параметр шаблона шаблона.
Я неверно истолковываю цель ограничений для параметра шаблона шаблона параметры?