当前位置: 首页 > 知识库问答 >
问题:

如何确定函数专业化的主模板?

艾奕
2023-03-14

函数模板专门化的主模板通常很直观,然而,我正在寻找形式规则来理解更令人惊讶的情况。例如:

template <typename T, typename U>
void f(T, U) {}     // (1)

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

template <>
void f(int, int) {} // (3); specializes (2), not (1); why?

理论上,(3)也可以是(1)的特化,但实验表明不是。

共有2个答案

荆树
2023-03-14

主题似乎是模板“部分排序”。可以在这里找到一个示例:模板推导中的部分排序过程是什么

颜安宁
2023-03-14

让我们重点关注泛型模板(1)和(2)的声明。这是两个不同的模板,例如,(2)不是(1)的特化。好的,现在当我们编写一个专门化时:

template <>
void foo(int, int) {}

在推断要专门化哪个模板时,编译器将识别两个候选模板。然后,它必须选择最合适的。这种选择的过程称为“函数模板的偏序”。所选报价:

当同一函数模板专门化匹配多个重载函数模板时(这通常是模板参数推导的结果),将对重载函数模板执行偏序以选择最佳匹配。

让我们调用匹配模板集。然后,对于S中的每一对(f1,f2),编译器将通过在其类型(对应的非类型)参数上应用伪类型(对应的值)来转换f1。然后它尝试将其与f2匹配。然后它通过变换f2并尝试将其与f1匹配来执行相同的过程。最后,在检查每一对之后,编译器可以确定哪一个模板候选者是最专业的。如果没有做到这一点,编译就会失败。

在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:

  • 转换(1)应用于(2):表示foo,T=T1,U=T2。尝试匹配(2):扣除失败
  • 转换(2)应用于(1):foo(T1,T1),当应用于(1)时,它解析为T=T1和U=T1

从这个过程中,编译器推断出(2)比(1)更专业化,您的专业化适用于(2)。当编译器关注于特定调用时,在重载解析期间也会应用相同的过程。

下面是说明所有这些过程的示例(摘自@Yakk的评论):

template <typename T, typename U>
void f(T, U) { std::cout << "f(1)\n"; }     // f(1)

template <typename T>
void f(T, T) { std::cout << "f(2)\n"; }     // f(2)

template <>
void f(int, int) { std::cout << "f(3)\n"; } // f(3); specializes f(2), not f(1); why?

// Now the same specialization but without any template overload...
template <typename T, typename U>
void g(T, U) { std::cout << "g(1)\n"; }     // g(1)

template <>
void g(int, int) { std::cout << "g(3)\n"; } // g(3); No ambiguity, specializes g(1)

接下来,让我们执行几个调用:

f(1, 1);            // Prints f(3)
f<int>(1, 1);       // Prints f(3)
f<int, int>(1, 1);  // Prints f(1)
f(0.1, 0.2);        // Prints f(2)

g(1, 1);            // Prints g(3)
g<int, int>(1, 1);  // Prints g(3)

所有这些都可以在这里看到——摘自@Yakk的评论。

 类似资料:
  • 我有以下模板方法: 但是我得到了那些奇怪的链接错误: /usr/lib/gcc/x86_64-redhat-linux/4.4。7/../../../../包括/c/4.4。7/例外:62:void MyStruct::readField(std::basic_istream)的多重定义 如何专门化此成员函数? 编辑 这种方法在以下方面起作用: 或者使用s或在类外使用

  • 在本文中,他们说(c)是(b)的显式专门化。我的疑问是,为什么我们不能说它是(a)的显式专门化?因为我们可以为任何特定类型专门化模板。所以,当专门化int*时,为什么他们说(c)显式专门化(b)。 任何评论都将有助于理解事情。

  • 问题内容: 这是我的代码: 它运作良好。但是当我尝试添加这个 我遇到编译器错误:«int MyClass :: DoSomething()»的«>»令牌模板标识«DoSomething <0>»之前的无效显式专门化与任何模板声明都不匹配 我使用g ++ 4.6.1应该怎么做? 问题答案: 不幸的是,如果不对外部模板进行特殊化处理,就不能对作为类模板成员的模板进行特殊处理: C ++ 11 14.7

  • 我有一个程序如下。有一个基本模板,以及SFINAE的部分专业化。 在2运行程序时,将打印 中的

  • 顺便说一句,我确实编译了以下内容,但是专门化在运行时没有像预期的那样工作。基类型和派生类型最终要经历的非专用版本。 正确的语法是什么?

  • 我试图编写一个可变函数模板来计算的字节大小。这将用于一个网络编程项目,我正在工作。第一步,我在没有工作的variadic模板的情况下想出了这个: 错误代码#2。如果我将variadic模板放在不同的位置: 我得到了 错误:重载的'size t ()'调用不明确