看来理解模板模板参数会杀了我:(,让我解释什么误解我在我的脑海中,使我困惑:
template<class T>
class B {}; // A templated class
下面是其他代码:
template<template<class X> class Z = B> // The problem is in this line for me
class BB{};
注意模板类BB的参数列表中的行,该行为:
template<class X> class Z = B
现在,是什么阻止了C++认为Z不是另一个模板类Z呢?
即:
template<class X> class Z {
}
而不是认为类Z本身是模板化参数。
3条答案
按热度按时间avkwfej41#
曼卡斯已经回答了你的问题,但我想我还是要插一句。
模板template参数就像普通的模板类型参数一样,不同之处在于它们匹配的是模板而不是具体类型:
如果有帮助的话,你可以把它们想象成函数指针,普通函数只接受参数,就像普通模板只接受类型一样,然而,一些函数接受接受接受参数的函数指针,就像模板模板类型接受接受接受类型的模板一样:
在评论中回答您的问题:template模板参数是不可能的。然而,它们不可能的原因仅仅是因为标准化委员会认为模板模板就足够了,可能是为了让编译器实现者的生活更轻松。也就是说,没有什么可以阻止委员会决定它们是可能的,那么像这样的东西将是有效的C++:
同样,您可以在函数指针中看到相似之处。
与
Baz
类似的函数为:你会在哪里使用模板模板模板?
这很牵强,但我能想到一个例子:一个非常通用的图形搜索库。
图搜索中的两种常见算法是深度优先搜索(DFS)和宽度优先搜索(BFS)。这两种算法的实现除了一点之外是相同的:DFS使用节点堆栈,而BFS使用队列。理想情况下,我们只需要编写一次算法,将堆栈/队列作为参数。此外,我们还需要指定堆栈或队列的实现容器,以便我们可以执行以下操作:
但是什么是栈或队列呢?就像在STL中一样,栈或队列可以用任何类型的容器来实现:向量、deque、列表等,并且还可以是任何元素类型的栈,因此我们的栈或队列将具有接口:
但是
Vector
和Deque
本身就是模板类型!最后,我们的
Stack
将是一个模板模板,如下所示:我们的
search
算法必须是一个模板模板!那会很激烈,但希望你能明白。
记住:模板模板模板不是法律的的C++,所以整个图搜索的东西实际上不会编译。它只是一个“如果?”:)
kgqe7b3p2#
这是该语言语法的一部分(它是畸形的并且大量依赖于上下文),如果
template<class X> class Z
出现在模板参数列表中,那么它被解释为声明了一个形式参数Z
,其类型为(类似于元类型;种类以与类型分类值相同的方式分类类型)“采用一个类参数的模板类”。92dk7w1h3#
可接受答案中的用法示例具有误导性,
特别是对于初学者。诚然,很难想出任何不需要人为设计的东西,但我们至少应该设计一些不与总体原则相矛盾的东西。模板参数应该只在我们界面的用户出于某种原因不能指定模板类型,而我们需要为他们指定模板类型时使用。在Stack示例中,我们要求同时使用Storage和Element,仅用该元素示例化存储,这是完全不必要的,用户可以容易地执行基本替换:
堆栈需要做的就是:
它不以任何方式为用户决定元素类型,因此不需要模板参数。
在这里,我想我们假设用户无法访问内部Graph::Node类型,并且search是Graph的一个朋友函数,这似乎有点道理。然而,我们真的需要用图节点填充结构吗,或者只是引用它们?用户可以不以任何方式引用节点吗?如果不可以,为什么它被称为图,而不是slow_unordered_set?所以让我们想象一下,他们可以访问一些节点引用/指针类型,然后他们可以这样做:
该函数进一步简化为:
天哪,现在它比以往任何时候都更通用了!你想为存储指定一个分配器吗?没问题,就这么做吧。你想用一些需要最大大小参数的静态分配向量吗?那就去吧。想从头开始实现堆栈吗?好吧,只要它像堆栈一样嘎嘎作响...
∮也许有个更恰当的例子∮
一个带有模板参数的模板的类可能是某个表示复杂系统的类,它使用某个存储模板来实现一系列内部结构,并且由于某种原因在该存储模板上进行了参数化:
如果你问我-这段代码很臭,但它不像我不会写它。
现在我们已经有了一个带有模板参数的模板的半恰当的例子,我们可以为一个带有模板参数的模板设计一些东西,这个模板本身也有一个模板参数:想象一下,我们最终得到了10个这样的系统类,它们都有相同的接口,都在存储模板上参数化,但在其他方面却非常非常不同。请为超级系统做好准备,超级系统是一个更复杂的类,它使用了我们的一系列系统,但关键是需要自己决定每个系统使用什么存储模板。
我们希望在这里处理的模板层次结构中指定一些内容,但仍保留一些可定制的内容。由于某些原因,我们不知道我们将处理的确切系统,但我们知道关于所有系统的一些非常具体的信息,我们绝对需要按照我们的方式进行。这是这些示例的一个总体主题,我们的目标不是使内容更加通用和可定制。但恰恰相反--我们希望锁定某些根深蒂固的东西。
TL; DR
根据我的经验,只有在深入研究元编程库时,您才会遇到带模板参数的模板的良好用例。如果你能认出这个模式
作为一个类型的函数,那么在这种心态下,你可以使用带有模板参数的模板,也许还可以考虑更深层次的东西。2否则,你会给自己一记耳光。