模板模板参数中使用命名参数有什么用处?

13

如果我需要定义一个带有模板模板参数的模板函数foo,我通常会按照以下方式进行:

// Notice that the template parameter of class T is unnamed.
template <template <typename> class T> void f() { std::cout << "Yay!\n"; }

注意,模板模板参数的模板参数未命名,但我们可以为该参数指定一个名称:
// Now the template parameter of class T is named INNER.
template <template <typename INNER> class T> void f(const INNER &inner)
{ std::cout << inner << " Yay!\n"; }

这似乎毫无用处,因为我不能在函数中引用INNER参数,上面的代码会产生以下错误:

错误:'INNER'不是一种类型

令人惊讶的是,typename INNER没有命名为类型,毕竟typename关键字是用来命名类型的。不过,这很容易修复:
// Now INNER is the name of the template parameter of class T and also
// the name of the second template parameter of foo.
template <template <typename INNER> class T, typename INNER> void f(const INNER &inner)
{ std::cout << inner << " Yay!\n"; }
// ...
f<std::valarray, int>(666); // Prints "666 Yay!"

但最终,INNER参数实际上不需要名称:

// Now the template parameter of class T is unnamed one more time,
// INNER is the name of the second template parameter of foo.
template <template <typename> class T, typename INNER> void f(const INNER &inner)
{ std::cout << inner << " Yay!\n"; }
// ...
f<std::valarray, int>(666); // Prints "666 Yay!"

而且(我相信您在我之前已经注意到了),模板-template参数中的名称被忽略了! 如果没有忽略,它应该与foo的第二个模板参数发生名称冲突,不是吗?

参数模板-template参数名称被忽略的另一个演示:

// Now T is the name of the template parameter of class T and also
// the name of the template parameter of foo!
template <template <typename T> class T> void f()
{ std::cout << "Yay!\n"; }
// ...
f<std::valarray>(); // prints "Yay!"

被称为T的类型同时被模板-模板参数和模板-模板本身使用?我认为不是这样的,据我所知,模板-模板参数中的名称会被忽略。
那么,问题是什么?
  1. 我的猜测正确吗?模板-模板参数的命名模板参数的名称会被忽略吗?
  2. 如果我错了,我误解了整个事情,那么在模板-模板参数中使用命名参数有用吗?您能提供一些有用的示例吗?
至于关于问题2的有用示例,我指的是只能通过使用模板-模板参数的命名模板参数才能实现的某些内容。

1
我认为阅读这个 QA:https://dev59.com/questions/vXVC5IYBdhLWcg3wsTRi 将有助于解释为什么没有必要给模板 - 模板参数命名。 TTP 实质上是声明了一个带有模板的参数的签名,而不是为模板方法提供额外的模板参数。类似于声明函数对象时,它是 (*foo)(type, type type),而不是 (*foo)(type 名称, type 名称, type 名称) - aruisdante
1个回答

12

[basic.scope.temp]/p1:

模板template-parameter的名称的声明区域是引入该名称的最小template-parameter-list

(现在试着说10遍这句话。)

它可以在该列表内使用。例如,

template < template<class T, T t> class TP > class foo {};
//                           ^  ^-----T's scope ends here
//                           |
//                           T can be used here

foo<std::integral_constant> bar;

顺便说一下,这与函数声明非常相似。以下通过产生编译器错误来说明这种类比:void f(int x, decltype(x)); int main() { f(1, nullptr); }。以下编译和链接正常:void f(int x, decltype(x)); int main() { f(1, 1); } void f(int, int) {}。这是因为x的作用域恰好足以包含其后面的decltype - Christian Hackl
好的,我错了:模板-模板参数的命名参数并没有被忽略,它只是在其模板-模板类之外不存在...我能想到的命名模板-模板参数的唯一用途是以下内容:template <template <typename T, typename = std::allocator<T>> class V> class f {}; - PaperBirdMaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接