有时我会在下面看到一种声明:
template<typename> // <-- not "typename T"
struct A { ... };
此类声明的用例是什么?那些有用还是只是风格问题?
答案 0 :(得分:5)
您是否真的看到用于模板定义,而不是仅用于模板声明?
一些用途:
// 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)
{ ... }
约翰内斯给出了你所联系到的特殊情况的解释,但显然你发现它并不令人满意。我将带你了解它的工作原理。让我们假设一个任意的特质类:
// 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
。让我们通过添加秘密成分使我们的课更有用:
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_
不是SFINAE,trait<T, void>
扮演的角色始终具有{{1}}形式的特化。因为我们根本不关心使用type参数,所以它没有命名。
答案 1 :(得分:1)
这可以从type - &gt;创建编译时映射。 A
的静态成员。
template<typename>
struct sort_statistics { static size_t times_comparator_called = 0; };
template<typename T>
size_t sort_statistics<T>::times_comparator_called;
template<typename Titer>
void my_sort( Titer first, Titer last )
{
//...
++sort_statistics<iterator_traits<Titer>::value_type>::times_comparator_called;
if (*itA < *itB) {
//...
}
它仍然可以专业化。