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
,但这是完全正确的
什么传递它作为模板模板参数现在允许。
我是否误解了模板模板参数的约束目的 参数Δ
答案 0 :(得分:9)
这是提案中的错误。约束模板模板参数应接受具有较弱约束的参数。
答案 1 :(得分:1)
这是猜想,但这似乎是一个可能的解释:
允许传递更具体的模板,而不是更通用的模板,是规则目前在可变参数模板模板参数方面的工作方式。您可以传递一个单类型参数模板,其中需要一个可变参数:
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