英文:
How to differentiate between the different types of C++ specializations when writing/speaking
问题
我认为我对“专门化”一词的困惑部分在于它似乎有两个相关但不同的含义。我似乎遇到了以下两个定义:
来自IBM模板实例化:
从模板实例化创建的用于处理特定一组模板参数的定义称为专门化。
这似乎意味着,如果我有一个模板类:
template <typename T>
class Foo { ... };
我可以通过简单地实例化 Foo<int>
来创建 Foo
的专门化,例如。 这是有道理的,因为模板只是一个原型,编译器会从中为 int
创建一个专门化的定义。
然而,我也见过模板专门化指的是一个不同的概念。有时它似乎被称为完全模板专门化,而在其他情况下,它似乎被称为部分模板专门化。这似乎是指为模板参数的一个子集指定单独的“专门化”代码的行为。所以假设我有一个非常牵强附会的例子,我希望 getMagnitude()
对除了 uint8_t
之外的所有类型返回某个值,对于 uint8_t
的情况,我想首先将该值除以 255。我可以这样写:
template <typename T>
float getMagnitude(T value)
{
return static_cast<float>(value);
};
template <typename T>
float getMagnitude<uint8_t>(T value)
{
return static_cast<float>(value)/255.f;
};
这样,我仍然有一个用于 getMagnitude()
的模板,但我可以将其专门化以针对不同的模板参数采取不同的行为。这也解释了为什么它被称为专门化,因为它是为特定的模板参数定制行为。
然而,在线上和与其他人交谈时,似乎这种术语并不总是很清楚(至少对我来说是这样)。这是否应该仅从上下文中清楚地了解?或者在谈论/编写文档时是否有一种区分这两种类型的模板专门化的方法?(并且进一步地,我是否可能不知道的其他类型的模板专门化?)
英文:
I think some of my confusion over what "Specialization" means is that it appears to have two related, though distinct meanings. These are the two definitions I've seem to come across:
From IBM Template Instantiation
> The definition created from a template instantiation to handle a specific set of template arguments is called a specialization.
Which seems to mean, if I have some templated class:
template <typename T>
class Foo { ... };
That I create a specialization of Foo
by simply instantiating Foo<int>
for example.
This makes sense, as the template is merely a prototype, from which the compiler is creating a specialized definition specifically for int
.
However, I have also seen template specialization referring to a different concept. Sometimes it seems to be called Full template specialization, while others it seems to be called partial template specialization. This seems to be the act of specifying separate "specialized" code for a subset of template arguments. So say I have this really contrived example where I want getMagnitude()
to return some value for all types except for uint8_t
, for which case I'd want to to first divide the value by 255. I could write this as:
template <typename T>
float getMagnitude(T value)
{
return static_cast<float>(value);
};
template <typename T>
float getMagniude<uint8_t>(T value)
{
return static_cast<float>(value)/255.f;
};
That way I still have a template for getMagnitude()
but I can specialize it to behave differently for different template arguments. This also makes sense why it'd be called specialization, as it is specializing the behavior for certain template arguments.
Online and talking with other people though, it seems like this terminology isn't always clear (at least not to me). Is it the type of thing that should be clear from context alone? Or is there a way of differentiating between these two types of template specialization when speaking/writing documentation? (And further, are there possibly other types of template specialization I'm not aware of?)
答案1
得分: 2
术语非常清晰和精确。实例化和特化是不同的概念,可以都是隐式的或显式的。
专门化是一个类、变量、函数或类成员,要么是从一个模板实体实例化的 ([temp.inst]),要么是从一个模板实体的显式专门化 ([temp.expl.spec])。
这就是你从IBM文档中引用的含义。实例化(显式或隐式)是生成专门化的一种方式。另一种方式是显式专门化。请注意,隐式专门化不会在代码中找到。相反,如果需要(由实例化要求),它会在编译时生成。
除非类模板专门化是已声明的专门化,在引用需要完全定义的对象类型或在类类型的完整性影响程序语义的上下文中引用专门化时,将隐式实例化类模板专门化。
实例化可以是隐式的(就像在你的示例中使用Foo<int>
时一样),这由上面的引用所覆盖,也可以是显式的,这由下面的引用所覆盖。
可以从其模板显式实例化类、函数、变量或成员模板专门化。可以从与其类模板关联的成员定义显式实例化类模板的成员函数、成员类或静态数据成员。
例如:
template <typename T>
class Foo { ... };
template class Foo<int>; // 显式实例化
再次强调,这不是显式专门化,因此编译器会生成专门化本身。您不提供任何实现,它来自模板。
显式专门化 ([temp.expl.spec]
) 是你完全编写的东西。在你的(无效)示例中,使用getMagnitude
,它将如下所示:
template <typename T>
float getMagnitude(T value)
{
return static_cast<float>(value);
};
template <> // 无模板参数
float getMagnitude<uint8_t>(uint8_t value) // 显式类型,没有 `T`
{
return static_cast<float>(value)/255.f;
};
在这里,getMagnitude<uint8_t>
是函数模板 getMagnitude
的显式专门化。您提供了实现。
这也被称为显式 完全 模板专门化,因为所有模板参数都被赋予了类型或值。它不再是一个模板。
类也可以这样做。但是,与函数不同,您还可以对类进行部分 专门化。这被称为类模板部分专门化。
类模板的部分专门化为模板提供了替代定义,当专门化中的参数与部分专门化中给出的参数匹配时,将使用该替代定义 ([temp.class.spec.match])。
还有重要的一点:
每个类模板的部分专门化都是一个不同的模板,并且必须为模板部分专门化的成员提供定义 ([temp.class.spec.mfunc])。
示例:
template <typename T, typename U>
class Foo { ... };
template <typename V>
class Foo<V, V> { ... }; // 当 T 和 U 相同时的部分专门化
请注意,部分专门化仍然是一个模板:它需要至少一个模板参数(在这种情况下是 typename V
,其中 V
也可以被替换为 T
)。
英文:
The terminology is very clear and precise. Instantiation and specialization are different concepts, and can both be implicit or explicit.
[temp.spec]
> A specialization is a class, variable, function, or class member that is either instantiated ([temp.inst]) from a templated entity or is an explicit specialization ([temp.expl.spec]) of a templated entity.
This is what your quote from the IBM documentation means. Instantiation (explicit or implicit) is one way to produce a specialization. The other way is explicit specialization. Note that an implicit specialization is not to be found in the code. Instead, it is produced at compile-time if necessary (required by an instantiation).
[temp.inst]
> Unless a class template specialization is a declared specialization, the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.
Instantiation can be implicit (like when using Foo<int>
in your example), which is covered by the quote above, or explicit, which is covered by the quote below.
[temp.explicit]
> A class, function, variable, or member template specialization can be explicitly instantiated from its template.
A member function, member class or static data member of a class template can be explicitly instantiated from the member definition associated with its class template.
For example:
template <typename T>
class Foo { ... };
template class Foo<int>; // explicit instantiation
Again, this is not an explicit specialization, so the compiler generates the specialization itself. You don't give it any implementation, it comes from the template.
An explicit specialization ([temp.expl.spec]
) is something you write in full. In your (invalid) example with getMagnitude
, it would look like this:
template <typename T>
float getMagnitude(T value)
{
return static_cast<float>(value);
};
template <> // no template parameter
float getMagnitude<uint8_t>(uint8_t value) // explicit types, no `T` anywhere
{
return static_cast<float>(value)/255.f;
};
Here, getMagnitude<uint8_t>
is an explicit specialization of the function template getMagnitude
. You provide the implementation.
This is also known as explicit full template specialization, because all the template parameters are given a type or value. It is no longer a template.
The same can be done with classes. However, you can also partially specialize classes, unlike functions. This is known as class template partial specialization.
[temp.class.spec]
> A partial specialization of a class template provides an alternative definition of the template that is used instead of the primary definition when the arguments in a specialization match those given in the partial specialization ([temp.class.spec.match]).
Also important:
> Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization ([temp.class.spec.mfunc]).
Example:
template <typename T, typename U>
class Foo { ... };
template <typename V>
class Foo<V, V> { ... }; // partial specialization for when T and U are the same
Note that the partial specialization is still a template: it requires at least one template parameter (typename V
in this case, where V
could also be replaced by T
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论