模板模板参数和转发参考

时间:2017-08-21 06:56:09

标签: c++ language-lawyer

假设我们有以下代码:

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。我偶然发现了thisthat个问题,但我在答案中没有看到任何真实的证据。

上述链接的答案以及此问题的答案断言Container<T>无法计入模板参数。我认为没有理由这样做。让我们的例子更简单:

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

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

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

但是以完全不同的方式对待它。为什么?为什么Container<>&&template <typename=int> class ContainerContainer&&的{​​{1}}被认为是同一件事?

2 个答案:

答案 0 :(得分:11)

术语&#34;转发参考&#34;在[temp.deduct.call/3](来自C ++ 17 draft n4659)中描述:

  

转发引用是对cv-nonqualified的右值引用   模板参数,它不代表a的模板参数   类模板(在类模板参数推导期间)。

在您的示例中,Container<T>不是模板参数,它是您根据模板参数TContainer组成的类型。为了使引用真正转发,您只能使用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 Ttemplate <typename> class Container。为每个参数命名的标识符为TContainerT命名第一个参数,Container命名第二个参数。 Container<T>不是标识符,也不是两者的名称。