有时我会看到下面的声明:
template<typename> // <-- not "typename T"
struct A { ... };
此类声明的用例是什么。这些是有用的还是只是风格问题?
最佳答案
您真的看到它用于模板定义,而不是用于模板声明(仅)吗?
一些用途:
// declaration only: the parameter name has no use beyond documentation
template<typename>
struct A;
// this is fine
template<typename T>
void eat_an_a(A<T> a);
// later, we can name the parameter to use it
template<typename T>
struct A { ... };
// C++0x only
template<
typename T
// We don't care for the actual type (which will default to void)
// the goal is sfinae
, typename = typename std::enable_if<
std::is_array<typename std::decay<T>::type>::value
>::value
>
void
f(T&& t);
// We still don't care to name that defaulted parameter
template<typename T, typename>
void f(T&& t)
{ ... }
Johannes 已经对您所链接的特定案例进行了解释,但显然您发现它并不令人满意。我将向您介绍这是如何工作的。让我们假设一个任意特征类:
// no definition
template<typename TypeToExamine, typename ImplementationDetail = void>
struct trait;
我正在详细说明类型参数在它们的名称中的作用。现在这个声明允许的,因为第二个参数是默认的,是一点语法糖。无论在哪里trait<U>
出现,它完全就好像我们写了trait<U, void>
已经写好了。现在让我们为特征的基本情况提供一个定义:
// assume previous declaration is still in scope so we do not default
// the second parameter again
template<typename T, typename> struct trait: std::false_type {};
这不是一个非常有用的特性。现在当我们写 trait<U>
, 这是 trait<U, void>
的缩写,我们最终得到这个定义。这意味着 trait<U>::value
是有效的,实际上是 false
.让我们通过添加 secret 成分使我们的类更有用:
template<typename> struct void_ { typedef void type; };
// again, assume previous declarations are in scope
template<typename T, typename void_<decltype( T() + T() )>::type>
struct trait: std::true_type {};
同样,当我们写 trait<U>
, 就好像我们写了 trait<U, void>
.部分特化不会改变这一点(这是不允许的)。但是我们在查询trait<U>::value
时应该使用什么定义呢? ?好吧,首先,我们必须知道专业应该匹配什么;或者,神秘的第二个参数是什么 typename void_<decltype( T() + T() )>::type
?
最简单的情况是 U() + U()
是病式的。然后 SFINAE 介入,就好像特化不存在一样;因此我们得到了非专业定义,并且value
是false
.但是如果U() + U()
是良构的,那么decltype
产生一个类型,整体变成 void
, 因为对于所有类型 void_<T>::type
是void
.所以这意味着我们有一个形式的特化 trait<T, void>
.这可以匹配 trait<U>
, 简单匹配 T
与 U
.现在value
是true
.
但是如果专门化已经被编写
template<typename T>
struct trait<T, decltype( T() + T() )>: std::true_type {};
那么唯一使用它的方法就是写trait<U, decltype(U() + U())>
, 除非 decltype(U() + U())
碰巧是空的。记住,trait<U>
是糖 trait<U, void>
.所以trait<int>
永远不会匹配我们的专业,因为后者的形式是 trait<int, int>
.
因此 void_
扮演的角色总是具有 trait<T, void>
形式的特化如果他们不是 SFINAE 就出来了。因为我们根本不关心使用类型参数,所以它没有命名。
关于c++ - 不在模板中声明类型名称的用例是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6561212/