假设我们有以下代码:
template<typename T>
class C
{};
template <typename T, template <typename> class Container>
void dummyMe(Container<T>&&)
{};
int main(int argc, char* argv[])
{
C<int> c;
dummyMe(c);
return 0;
}
由于第一个dummyMe
参数是rvalue-reference,因此无法编译。有人可以在Standardese中解释为什么模板模板参数与转发参考不相符,为什么它用简单的英语。
P.S。我偶然发现了this和that个问题,但我在答案中没有看到任何真实的证据。
上述链接的答案以及此问题的答案断言Container<T>
无法计入模板参数。我认为没有理由这样做。让我们的例子更简单:
template <template <typename=int> class Container>
void dummyMe(Container<>&&)
{};
现在我们有一个几乎与以下相同的例子:
template <typename Container>
void dummyMe(Container&&)
{};
但是以完全不同的方式对待它。为什么?为什么Container<>&&
与template <typename=int> class Container
到Container&&
的{{1}}被认为是同一件事?
答案 0 :(得分:11)
术语&#34;转发参考&#34;在[temp.deduct.call/3](来自C ++ 17 draft n4659)中描述:
转发引用是对cv-nonqualified的右值引用 模板参数,它不代表a的模板参数 类模板(在类模板参数推导期间)。
在您的示例中,Container<T>
不是模板参数,它是您根据模板参数T
和Container
组成的类型。为了使引用真正转发,您只能使用T&&
。虽然Conatiner
是模板参数,但您无法引用模板(以上段落甚至明确提及)。 类型 Container<T>
与模板 Container
不同。它是一个实例化的类。 1
虽然您可以使用SFINAE获取只能绑定到容器类型的转发引用,但我个人觉得您最好只重载该功能。
template <typename T, template <typename> class Container>
void dummyMe(Container<T>&&)
{}
template <typename T, template <typename> class Container>
void dummyMe(Container<T>&)
{}
<子> 1 [temp.spec/2] - 从类模板实例化的类称为实例化类 子>
答案 1 :(得分:6)
上述链接的答案以及此问题的答案断言
Container<T>
不能算作模板参数
什么是或不是模板参数不需要太多解释。它在[temp.param]
中明确定义:
template-parameter:
type-parameter
parameter-declaration
type-parameter:
type-parameter-key ...(opt) identier (opt)
type-parameter-key identier(opt) = type-id
template < template-parameter-list > type-parameter-key ...(opt) identier(opt)
template < template-parameter-list > type-parameter-key identier(opt) = id-expression
type-parameter-key:
class
typename
从这些生产规则可以清楚地看出,dummyMe
只有两个模板参数:typename T
和template <typename> class Container
。为每个参数命名的标识符为T
和Container
。 T
命名第一个参数,Container
命名第二个参数。 Container<T>
不是标识符,也不是两者的名称。