这个模板构造是什么
What is this template construct?
这来自VS2012附带的C++标准库xutility标头。
template<class _Elem1,
class _Elem2>
struct _Ptr_cat_helper
{ // determines pointer category, nonscalar by default
typedef _Nonscalar_ptr_iterator_tag type;
};
template<class _Elem>
struct _Ptr_cat_helper<_Elem, _Elem>
{ // determines pointer category, common type
typedef typename _If<is_scalar<_Elem>::value,
_Scalar_ptr_iterator_tag,
_Nonscalar_ptr_iterator_tag>::type type;
};
具体来说,第二个_Ptr_cat_helper声明的性质是什么?声明符_Ptr_cat_helper后面的尖括号使它看起来像一个特殊化。但是,它并没有指定专门化模板的完整或部分类型,而是多次重复模板参数。
我想我以前没见过。它是什么?
更新
我们都清楚,专门化适用于模板的实例化,其中两个模板参数都是相同类型的,但我不清楚这是构成完全专门化还是部分专门化,也不清楚为什么。
当所有模板参数都是显式提供的或由默认参数提供的,并且完全按照提供的方式用于实例化模板时,我认为专业化是完全专业化,相反,专业化是部分的,如果不是所有模板参数是必需的,因为专业化提供了一个或多个(但不是全部)模板参数,和/或模板参数是否以被专门化模式修改的形式使用。例如
一个部分的专门化,因为该专门化提供了至少一个(而不是全部)模板参数。
template<typename T, typename U>
class G { public: T Foo(T a, U b){ return a + b; }};
template<typename T>
class G<T, bool> { public: T Foo(T a, bool b){ return b ? ++a : a; }};
部分专用化,因为该专用化导致所提供的模板参数只能部分使用。
template<typename T>
class F { public: T Foo(T a){ return ++a; }};
template<typename T>
class F<T*> { public: T Foo(T* a){ return ++*a; }};
在该第二示例中,如果使用A<char*>;则模板中的T实际上是char类型,即所提供的模板参数仅部分由于专用化模式的应用而被使用。
如果这是正确的,那么这难道不会使原始问题中的模板成为完全专业化而不是部分专业化吗?如果不是这样,那么我的误解在哪里?
当为两个参数传递相同类型时,它是部分类模板专用化。
也许这会更容易阅读:
template<typename T, typename U>
struct is_same : std::false_type {};
template<typename T>
struct is_same<T,T> : std::true_type {};
编辑:
当你怀疑专业化是显式(完全)专业化还是部分专业化时,你可以参考这个问题上非常清楚的标准:
n3337,14.7.3./1
以下任何一项的明确专业化:
[…]
可以通过CCD_ 1引入的声明来声明;即:
显式专业化:
template < >
声明
和n3337,14.5.5/1
主类模板声明是指类模板名称是一个标识符。模板声明,其中类模板名称是简单模板id是分部simple-template-id中命名的类模板的专门化[…]
其中简单模板id在语法中定义如下:
简单模板id:
模板名称<模板参数列表opt>
模板名称
标识符
所以,无论哪里有template<>
,它都是完全专业化,其他任何东西都是部分专业化。
您也可以这样想:完全模板专门化专门用于主模板的一个可能的实例化。其他任何事情都是部分专业化。您问题中的示例是部分专门化,因为尽管它限制了参数的类型相同,但它仍然允许模板实例化有无限多个不同的参数。
像这样的专业化,例如
template<>
vector<bool> { /* ... */ };
是完全专业化,因为它在类型为bool
且仅为bool
时生效。
希望能有所帮助。
我觉得这是值得一提的。我想你已经知道了——函数模板不能局部专业化。而这个
template<typename T>
void foo(T);
template<typename T>
void foo(T*);
乍一看,foo
可能是指针的部分专用化,但事实并非如此——这是一个重载。
您提到在执行模板的专门化时指定"完整或部分类型",这表明您知道类模板的局部专门化等语言功能。
部分专业化具有相当广泛的功能。它并不局限于简单地为一些模板参数指定具体的参数。它还允许为某些参数类型组定义专用版本的模板,基于它们的cv资格或间接级别,如以下示例所示
template <typename A, typename B> struct S {};
// Main template
template <typename A, typename B> struct S<A *, B *> {};
// Specialization for two pointer types
template <typename A, typename B> struct S<const A, volatile B> {};
// Specialization for const-qualified type `A` and volatile-qualified type `B`
它还涵盖了基于某些模板参数是相同还是不同的专业化
template <typename A> struct S<A, A> {};
// Specialization for two identical arguments
template <typename A> struct S<A, A *> {};
// Specialization for when the second type is a pointer to the first one
作为另一个相当奇怪的例子,多参数模板的部分专业化可以用来完全覆盖主模板
template <typename A, typename B> struct S<B, A> {};
// Specialization for all arguments
现在,返回到您的代码示例,两个相同参数的部分专用化正是您发布的代码中使用的。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么