为什么模板模板参数不允许在参数列表后使用"typename"
Why does not a template template parameter allow 'typename' after the parameter list
模板模板typename?
当使用模板模板语法如template <template <typename> class T>
时,需要使用关键字class
,因为使用typename
会产生以下错误:
错误:template模板形参需要在形参列表后面加上class
在其他地方,关键字typename
和class
在声明模板形参的基本情况下是可互换的。
你可以争辩说,当使用模板模板时的要求是一个提示,你期望传递一个类类型,但情况并非总是如此(特别是在c++ 11引入模板类型别名之后)。
template <template <typename> class T> // 'class' keyword required.
struct Foo {
using type = T<int>;
};
template <typename T>
using type = T (*)();
using func_ptr_t = Foo<type>::type;
这背后的原因是什么?
- 是否有任何具体的原因,为什么
typename
是不允许在模板模板声明? c++标准对此有什么规定吗?简短的回答:因为标准这么说。
较长的答案:在标准化之前,c++模板要求所有模板参数都使用class
关键字。然而,为了强调模板也可以是非类(即内置)类型,我们引入了另一个关键字typename
。然而,在c++ 98中,模板模板参数只能是类类型的,这就是没有在该上下文中添加typename
关键字的原因。
进入c++ 11和它的新特性模板别名,现在也引入了非类模板,因此非类模板模板参数:
template<typename T> struct A {};
template<typename T> using B = int;
template<template<typename> class X> struct C;
C<A> ca; // ok
C<B> cb; // ok, not a class template
template<template<typename> typename X> struct D; // error, cannot use typename here
上面的例子取自当前c++ 1z提案N4051标题为允许typename
在模板模板参数中,并建议精确地允许。
Clang 3.5 SVN现在支持这个与-std=c++1z
标志。
我正在寻找这个限制背后的理性[…]
在c++ 11引入之前,唯一可以传递给模板模板形参的模板是类模板。这就是强制使用关键字class
的原因。此外,关键字typename
意味着模板参数是对任意类型的替代,而不是模板,因此在该上下文中使用typename
只会模糊类型和(类) 模板之间的界限。这是可以理解的。
class
的强制执行或多或少已经过时了。提案N4051选择用c++ 1Z来改变这一点。
相关文章:
- 如何将一个使用参数包和typename的类作为函数(c++)的输入参数
- 将TypeName作为参数()作为参数()
- 使用 "typename Container::value_type" 作为返回值时无法推断模板参数
- 为什么可变参数模板在模板介绍中不起作用,但在要求子句中起作用?ConceptName{T,U,V,W} <-- template<typename ...T>
- 模板成员转换运算符,默认模板参数到与 TypeName 绑定的函数
- 模板参数typename和非typename之间的区别
- 如何将"std::array"用于"模板类"形式的模板参数<typename>?
- typename 参数的模板专用化是特定模板的任何实例化
- 缩短C++枚举成员的路径(使用 typedef 或 typename),以用作模板参数
- C++std::bind接受typename作为第一个参数
- 需要帮助来理解具有复杂typename参数的模板函数
- 模板参数列表中的额外 typename 关键字:是否有效
- 为什么在函数参数列表中重复typename关键字是必要的
- 在C++中作为参数传递的Typename
- 作为非typename参数的局部变量
- "typename qualified-id"引用非类型参数声明中的类型
- 模板typename为同一模板的其他参数的类型
- 带有模板参数或typename的模板函数
- 如果依赖名称用作模板参数,是否需要用typename限定该名称?
- 为什么模板模板参数不允许在参数列表后使用"typename"