N3580 describes the following scenario:
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;
Here, Regular is a refinement of Object; that is, every Regular is an
Object but not every Object is a Regular.
I would expect the type system to be such that for stack<X, Y> to be valid,
X must be an Object and Y must be instantiable with an Object. This
would mean that stack<int, my_vector> and stack<int, my_magic> are valid,
while stack<int, my_list> is not. Much like the case with normal functions:
struct Base {};
struct Derived : Base {};
void foo(Base* p, function<void(Base*)> fun) {
fun(p);
}
template<typename T>
void bar(T*);
I would expect that if p is a Base*, then foo(p, bar<Base>) and foo(p,
bar<void>) are valid, while foo(p, bar<Derived>) is not; after all, a
Base* has an implicit conversion to a void*, but not to a Derived*.
In the case of templates, though, the situation is the opposite. Only
stack<int, my_vector> and stack<int, my_list> are allowed, while stack<int,
my_magic> is forbidden. Why is this? my_magic works fine with any type,
while my_list may fail depending on what object I give it. Moreover, I can
trivially make my_magic work with only objects:
template<Object T>
struct my_restricted_magic : my_magic<T> {};
Now my_restricted_magic can be used with stack. On the other hand, there's
no easy way of making a my_list which accepts any type, but this is exactly
what passing it as a template template parameter now allows.
Am I misinterpreting the purpose of constraints on template template parameter's parameters?