Partial Specialization of function template

译自Function Templates Partial Specialization in C++
为什么C ++不允许对函数模板进行部分专业化?

1. function specialization vs overload

考虑一下,template specialization 归结为为给定类型选择正确的实现。并且解析发生在编译时。
现在将其与函数重载进行比较:它包括为给定类型的参数选择正确的函数。并且解析也发生在编译时。
从这个角度来看,这两个功能看起来非常相似。因此,通过函数重载可以达到与函数模板(部分或全部)专业化等效的功能,这是正常的。让我们用一个例子来说明。

考虑以下模板函数f:

template <typename T>
void f(T const& x)
{
    // body of f
}

假设当T为std::string时,我们需要特定的实现。
我们可以专门研究f:

template <>
void f<std::string>(std::string const& x)
{
    // body of f for std::string
}

或者我们可以只是重载

void f(std::string const& x)
{
    // body of f for std::string
}

无论哪种方式,当您传递字符串时,执行都会通过特定的实现。

partial specialization 也是如此。假设我们想要vector的f的特定实现。我们不能使用partial specialization来编写它,因为以下内容是非法的:

// Imaginary C++
template <typename T>
void f<std::vector<T>>(std::vector<T> const& v)
{
    // body of f or vectors
}

但是我们可以通过重载实现

template <typename T>
void f(T const& x) // #1
{
    // body of f
}
 
template <typename T>
void f(std::vector<T> const& v) // #2
{
    // body of f for vectors
}
 
f(std::vector<int>{}); // this call goes to #2

而且我们也获得了预期的效果。

2. 何时不能用overload

这是否意味着不存在对模板函数进行部分专业化的情况?没有!在某些情况下,超载不可以实现。

重载适用于模板参数,可以说是占据了模板函数用例的相当一部分。但是,如果模板不在参数中怎么办?例如,它可以是函数的返回类型:

模板<typename T>
T f(int i,std::string s)
{
    // ...
}

甚至在函数原型中都不存在:

template <typename T>
void f()
{
    // ...
}

这些情况之间的共同点是,必须在调用的位置显式地指定模板类型:

f<std::string>();

在这种情况下,重载是没有用处的,因此对于这种情况,我认为函数模板的Partial Specialization是适用的。Let’s review our options for working around the fact that C++ does not support it natively.

重载他是西蒙·布兰德(Simon Brand)提出的技术。 它包括添加一个参数,该参数携带有关T类型是什么的信息。 这个参数,类型,只是带有另一个类型T:

template <typename T>
struct type{};

(我们也可以在此处省略名称T,因为它并没有使用在模板的主体中。)
这可以返回到我们可以使用重载而不是Partial Specialization的情况。

请考虑以下示例。
我们想要设计一个模板函数create,该函数返回默认初始化的T类型的对象:

return T();

除了要返回的类型是向量时,在这种情况下,我们希望分配1000的容量以备重复的插入:

std::vector<T> v;
v.reserve(1000);
return v;

因此,我们需要一个默认的实现,并其中一个对所有T都使用一个vector 。换句话说,我们需要使用vector <T>来partially specialize f。
示例

template <typename T>
struct type{};
 
template <typename T>
T create(type<T>)
{
    return T();
}
 
template <typename T>
std::vector<T> create(type<std::vector<T>>)
{
    std::vector<T> v;
    v.reserve(1000);
    return v;
}
 
template <typename T>
T create()
{
    return create(type<T>{});
}

即使我们不能对函数模板做Partial Specialization,但可以对类模板做。 有一种方法可以通过重用后者来实现。

3. 不要混用Partial Specialization和重载

当对一组函数的多个实现使用一组重载时,我们可以了解发生了什么。

当您对一组函数的多个实现使用一组(全部)Partial Specialization时,我们也可以了解正在发生的事情。
但是,当将重载和专业化功能混合在一起使用时,您将进入魔术,伏地魔和百慕大三角生活的领域,一个事物以一种无法解释的方式表现的世界,在这个世界上,您最好不知道太多的解释,因为它们可能会使您陷入困境,并且您的大脑最终会进入墓地,并被刺穿黑暗魔法的尖刺刺穿。😃
为了说明这一点,请考虑一下/u/sphere991给出的有见地的示例,它说明了一切:

template <typename T> void f(T ); // #1
template <typename T> void f(T* ); // #2
template <> void f<>(int* ); // #3
f((int*)0); // calls #3

但是:

template <typename T> void f(T ); // #1
template <> void f<>(int* ); // #3
template <typename T> void f(T* ); // #2
f((int*)0); // calls #2 !!

重载和专业化声明的唯一顺序决定了调用的行为。 阅读这段代码会使我不寒而栗。😦
无论选择哪种技术,都不要将函数重载和Partial Specialization混为一谈。

4. 关于C++对Partial Specialization的支持

我们已经了解了何时需要对功能模板进行Partial Specialization以及如何对其进行仿真。 但是我们还没有回答我们最初的问题:为什么C ++不允许对函数模板进行Partial Specialization?
总结一下是 :该功能已被考虑了一段时间,并被忽略了,因为concept_maps可以代替它。 但是concept_maps是在后面的版本中也被放弃了!

我这样理解: 允许在C ++中对函数模板进行Partial Specialization这没有错,但是我们不知道是否有一天会使用它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值