为什么我似乎可以为函数模板定义部分特化?
我知道下面的代码是一个类的部分专业化:
template <typename T1, typename T2>
class MyClass {
…
};
// partial specialization: both template parameters have same type
template <typename T>
class MyClass<T,T> {
…
};
我还知道 C++ 不允许函数模板部分专业化(只允许完整)。但是我的代码是否意味着我已经部分地将函数模板专门用于一个/相同类型的参数?因为它适用于 Microsoft Visual Studio 2010 Express!如果不是,那么您能解释一下部分专业化的概念吗?
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
template <typename T1, typename T2>
inline T1 max (T1 const& a, T2 const& b)
{
return a < b ? b : a;
}
template <typename T>
inline T const& max (T const& a, T const& b)
{
return 10;
}
int main ()
{
cout << max(4,4.2) << endl;
cout << max(5,5) << endl;
int z;
cin>>z;
}
I know that the below code is a partial specialization of a class:
template <typename T1, typename T2>
class MyClass {
…
};
// partial specialization: both template parameters have same type
template <typename T>
class MyClass<T,T> {
…
};
Also I know that C++ does not allow function template partial specialization (only full is allowed). But does my code mean that I have partially specialized my function template for one/same type arguments? Because it works for Microsoft Visual Studio 2010 Express! If no, then could you please explain the partial specialization concept?
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
template <typename T1, typename T2>
inline T1 max (T1 const& a, T2 const& b)
{
return a < b ? b : a;
}
template <typename T>
inline T const& max (T const& a, T const& b)
{
return 10;
}
int main ()
{
cout << max(4,4.2) << endl;
cout << max(5,5) << endl;
int z;
cin>>z;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
根据标准,函数部分特化是不允许的。在这个例子中,你实际上是在重载&没有专门化
max
函数。如果允许的话,它的语法应该看起来有点如下:
在函数模板的情况下,仅允许完全专业化 C++ 标准。
有一些编译器扩展允许部分专业化,但在这种情况下代码会失去可移植性!
Function partial specialization is not allowed yet as per the standard. In the example, you are actually overloading & not specializing the
max<T1,T2>
function.Its syntax should have looked somewhat like below, had it been allowed:
In the case of a function templates, only full specialization is allowed by the C++ standard.
There are some compiler extensions which allows partial specialization, but the code looses its portability in such case!
由于不允许部分专业化(正如其他答案所指出的那样),您可以使用
std::is_same
和std::enable_if
来解决它,如下所示:输出:
编辑:如果您需要能够处理剩下的所有其他案例,您可以添加一个定义,声明已处理的案例不应匹配 - 否则您' d 陷入模糊的定义。定义可以是:
产生:
虽然这个所有情况看起来有点无聊,但因为你必须告诉编译器你已经完成的所有事情,所以处理最多 5 个或一个是相当可行的还有几个专业。
Since partial specialization is not allowed -- as other answers pointed --, you could work around it using
std::is_same
andstd::enable_if
, as below:Output:
Edit: In case you need to be able to treat all the other cases left, you could add a definition which states that already treated cases should not match -- otherwise you'd fall into ambiguous definitions. The definition could be:
Which produces:
Although this all-cases thing looks a bit boring, since you have to tell the compiler everything you've already done, it's quite doable to treat up to 5 or a few more specializations.
如果你真的想了解模板,你应该看看函数式语言。 C++ 中的模板世界是它自己的纯粹函数式子语言。
在函数式语言中,选择是使用模式匹配来完成的:
如您所见,我们重载了 isJust 的定义。
嗯,C++ 类模板的工作方式完全相同。您提供一个 main 声明,说明参数的数量和性质。它可以只是一个声明,也可以充当定义(您的选择),然后您可以(如果您愿意)提供模式的专业化并将它们关联到该类的不同(否则会很愚蠢)版本。
对于模板函数,特化有点尴尬:它与重载解析有些冲突。因此,已决定专业化将与非专业化版本相关,并且在重载决策期间不会考虑专业化。因此,选择正确函数的算法变为:
(对于内部模板)深度处理,请参见 GotW #49)
因此,函数的模板专门化是第二个 -地区公民 (字面上地)。就我而言,没有它们我们会更好:我还没有遇到过无法通过重载来解决模板专业化使用的情况。
不,这只是超载,这没关系。事实上,重载通常会按照我们期望的方式工作,而专业化可能会令人惊讶(记住我链接的 GotW 文章)。
If you really want to understand templates, you should take a look at functional languages. The world of templates in C++ is a purely functional sublanguage of its own.
In functional languages, selections are done using Pattern Matching:
As you can see, we overload the definition of
isJust
.Well, C++ class templates work exactly the same way. You provide a main declaration, that states the number and nature of the parameters. It can be just a declaration, or also acts as a definition (your choice), and then you can (if you so wish) provide specializations of the pattern and associate to them a different (otherwise it would be silly) version of the class.
For template functions, specialization is somewhat more awkward: it conflicts somewhat with overload resolution. As such, it has been decided that a specialization would relate to a non-specialized version, and specializations would not be considered during overload resolution. Therefore, the algorithm for selecting the right function becomes:
(for on in-depth treatment, see GotW #49)
As such, template specialization of functions is a second-zone citizen (literally). As far as I am concerned, we would be better off without them: I have yet to encounter a case where a template specialization use could not be solved with overloading instead.
No, it is simply an overload, and this is fine. In fact, overloads usually work as we expect them to, while specializations can be surprising (remember the GotW article I linked).
不允许非类、非变量部分专业化,但如上所述:
添加一个类来转发函数调用可以解决这个问题,下面是一个例子:
Non-class, non-variable partial specialization is not allowed, but as said:
Adding a class to forward the function call can solve this, here is an example:
我对迟到的答案感到抱歉,但我找到了一个解决方案,我在其他答案中没有看到解释(至少不是直接解释)。
函数不能部分专用,而类可以。
这里可以发挥作用的是类内的静态函数。
我们可以让它基本上在类专业化中移动“模板部分专业化”,并在其中创建标记为静态的函数。这将允许我们通过增加一点所需的代码行来构造我们的部分专用函数。
让我们考虑如下不可用的部分专用函数
Printer
(根本无法编译的代码)。我们可以使用静态类函数使其工作,并将部分特化转移到类上,如下所示:
它的结果有点长,但会以相对清晰的方式解决我们的问题。
您可以在 此处 在 godbolt 上进行测试。
------ 编辑:感谢KROy的提示
它可以通过仅包装两个静态来变得更短结构体内部的函数保留模板专门化:
它可以在 godbolt 这里。
I m sorry for the late answer, but i ve found a solution which i don't see explained (not directly at least) in the other answers.
A function cannot be partially specialized, while a class can.
What can do the trick here is a static function inside class.
We can make it works basically moving the "template partial specialization" inside a class specialization and creating inside it the function marked as static. This will allow us, by incrementing a bit the lines of code required, to construct our partially specialized function.
Let's consider the unavailable partially specialized function
Printer
as follow (code which doesn't compile at all).We can make it works using static class functions and moving the partial specialization on class instead like this:
It results a bit longer but would solve our issue with a relatively clear way.
You can test it on godbolt here.
------ EDIT : Thanks to KROy for the hint
It can be made even shorter by just wrapping the two static functions inside a struct leaving the template specialization on them:
It can be tested on godbolt here.
不可以。例如,您可以合法地专门化
std::swap
,但您不能合法地定义自己的重载。这意味着您无法使std::swap
适用于您自己的自定义类模板。重载和部分特化在某些情况下可以产生相同的效果,但远非全部。
No. For example, you can legally specialize
std::swap
, but you cannot legally define your own overload. That means that you cannot makestd::swap
work for your own custom class template.Overloading and partial specialization can have the same effect in some cases, but far from all.
迟到的答案,但一些迟到的读者可能会发现它很有用:有时,一个辅助函数 - 设计得可以专门化 - 也可以解决问题。
所以让我们想象一下,这就是我们试图解决的问题:
好吧,部分模板函数特化,我们不能这样做......所以让我们将特化所需的部分“导出”到辅助函数中,特化它一个并使用它:
这可能很有趣,特别是如果替代方案(正常重载而不是专门化,鲁本斯提出的解决方法,... – 并不是说这些不好或者我的更好,只是另一个一)将共享相当多的通用代码。
Late answer, but some late readers might find it useful: Sometimes, a helper function – designed such that it can be specialised – can solve the issue, too.
So let's imagine, this is what we tried to solve:
OK, partial template function specialisation, we cannot do that... So let's "export" the part needed for specialisation into a helper function, specialize that one and use it:
This can be interesting especially if the alternatives (normal overloads instead of specialisations, the workaround proposed by Rubens, ... – not that these are bad or mine is better, just another one) would share quite a lot of common code.