模板模板参数和转发引用

template template parameters and forwarding references

本文关键字:引用 转发 参数      更新时间:2023-10-16

假设我们有以下代码:

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参数是右值引用,因此无法编译。有人可以用标准语言解释我为什么模板模板参数与转发引用不相处,为什么用简单的英语如此。

附言我偶然发现了这个问题和那个问题,但我在答案中没有看到任何真正的证据。


上面链接中的答案和此问题的答案断言Container<T>不能计为模板参数。我看不出为什么会这样。让我们使示例更简单:

template <template <typename=int> class Container>
void dummyMe(Container<>&&)
{};

现在我们有一个几乎与以下内容相同的示例:

template <typename Container>
void dummyMe(Container&&)
{};

但这是以完全不同的方式对待的。为什么?为什么Container<>&&不能被视为template <typename=int> class ContainerContainer&&typename Container一回事?

术语"转发参考"在[temp.deduct.call/3](来自C++17草案n4659(中描述:

转发引用是对 cv 不合格的右值引用 不表示 的模板参数的模板参数类模板(在类模板参数推导期间(。

在您的示例中,Container<T>不是模板参数,而是您从模板参数TContainer组成的类型。为了使引用真正转发,您只能使用T&&。虽然Conatiner是模板参数,但不能引用模板(上面的段落甚至明确提到了它(。Container<T>的类型模板Container不同。这是一个实例化的类。

虽然您可以使用 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] - 从类模板实例化的类称为实例化类

上面

链接的答案和这个问题的答案断言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 Ttemplate <typename> class Container。命名每个参数的标识符TContainerT命名第一个参数,Container命名第二个参数。Container<T>不是标识符,并且不命名两者。