专业化功能模板和功能重载与类专业化

时间:2009-06-15 07:58:00

标签: c++ templates

根据Herb Sutter的this article,应该总是选择 Class Specializing 而不是功能过载,并且肯定会选择专业功能模板

原因是

  • 专业化不会超载。重载分辨率仅选择基本模板(或非模板函数,如果有的话)。只有在确定要选择哪个基本模板并且锁定了该选项之后,编译器才会查看是否恰好可以使用该模板的合适专用,如果是,则将使用专门化。
  • 我们不能专门针对功能模板。

我必须承认,在我阅读这篇文章之前,我曾几次撞到墙上。 他为什么不选择我的专业功能......
阅读完文章之后,我再也没有使用过专业功能模板。

示例:

template <class T> void foo( T t);

我们应该像这样编写foo,这样我们就可以使用类模板而不是函数专用来专门化它。

template<class T> 
struct FooImpl;

template <class T> void foo( T t) {
    FooImpl<T>::foo(t);
}

现在我们可以对模板进行特殊处理,而不必担心过载规则,我们甚至可以将模板专门化为这样的模板:

template<class U, class V> 
struct FooImpl< QMap< U, V > >;


以下是问题。

StackOverflow成员似乎更喜欢专业功能模板?
为什么呢? 因为专业功能模板比过载解决方案和类专业化获得了更多的赞成。
凭借我目前所获得的信息,我发现它有悖常理,因为我知道我能说得对,但我知道跟在我后面的人会碰壁。

已经有一些指向GOTWCA文章的链接,所以你必须阅读这篇文章。这意味着upvoters必须有一些额外的信息,请站起来赐教。

4 个答案:

答案 0 :(得分:4)

显式专门化函数模板的问题仅适用于函数也被重载的情况:

template <typename T> void foo (T*);   // #1

template <typename T> void foo (T);    // #2
template <> void foo<int*> (int*);

int main () {
  int * i;
  foo (i);  // Calls #1 not specialization of #2
}

如果没有#1重载,代码将按预期工作。但是,一个开始没有过载的函数可能会增加重载,因为代码将在未来保持。

这是其中一个例子,虽然我不想这么说,C ++有太多方法可以做同样的事情。就个人而言,如果你发现你需要专门化一个功能模板,那么我喜欢TimW在他对Neil Butterworth的answer的评论中提出的模式,即。最好通过让当前函数调用它来调用专门的类模板来实现:

template <typename T> class DoFoo {
    static void do (T) { /* default behaviour */ }
};
template <> class DoFoo<int*> {
    static void do (int*) { /* int * behaviour */ }
};

template <typename T> void foo (T t)
{
  DoFoo<T>::do (t);
}

如果'foo'超载,那么至少开发人员更清楚这个函数不会被调用,即。开发人员不需要成为标准专家就能知道专业化规则如何与重载决策相互作用。

然而,最终,编译器生成的代码将是相同的,这纯粹是开发人员的代码理解问题。

答案 1 :(得分:3)

你在这里假设SO选民都是大师 - 他们不是。 许多技术上不正确的答案得到了提升。

作为the answer that I think you are referring to的作者, 好吧,正如我在评论中所说,这不是问题 我关心(或知道)所有这些,因为我很少使用 模板专业化。我想可能已经删除了答案,但它在技术上是正确的,似乎确实引发了一些有关该主题的有用辩论。

请注意,它目前排在第三位(可能在此之后被低估了),并且已经接受了另一个使用完全不同的方法解决问题的答案。

答案 2 :(得分:2)

正如尼尔指出的那样,大多数正确的答案都会被投票。根据我的经验,已经在顶部的答案往往会得到更多的赞成。

至于原因:我猜专门的函数模板更容易理解,因此这就是使它们在示例代码中更受欢迎的原因。

答案 3 :(得分:2)

首先,我不是一个赞成者(无论你谈论什么)。

投票通常不保证正确;甚至有些不正确的答案被接受,加上赞成通常与发布特定答案的时间等有关。

对你的问题和文章:我已经阅读了这篇文章,我没有看到任何关于你建议的论点,这不适用于普通函数(模板)重载。如果您使用了函数模板特化(包括部分,如果允许的话),这个技巧基本上与编译器完全相同,具有Herb Sutter在文章中讨论的所有缺点。所以,我不认为你的方式是“正确的”(用你的话来说),我认为这是一种难以实现你不需要的方式。

比较

您的部分专业化:

template<class U, class V> 
struct FooImpl< QMap< U, V > >;

功能过载:

template<class U, class V> 
void foo(QMap< U, V > ) { ... }

即使SFINAE是可能的,函数(模板)部分排序遵循与模板特化解析几乎相同的规则...