通常来说,功能模板特化的主要模板是什么是非常直观的,但是,我正在寻找正式的规则来理解更令人惊讶的情况。例如:

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)的特化,但实验表明并非如此。

最佳答案

让我们集中讨论通用模板(1)和(2)的声明。
这是两个不同的模板,例如(2)不是(1)的特化。好的,现在当我们写一个特化的时候:

template <>
void foo(int, int) {}
当推导要专门化的模板时,编译器将识别出两个候选对象。然后,它必须选择最合适的。这种选择的过程称为"partial ordering of function templates"。选择报价:

让我们将S称为匹配模板集。然后,对于S中的每个对(f1,f2),编译器将通过在其类型(resp。non type)参数上应用伪类型(resp。value)来转换f1。然后,它尝试将其与f2匹配。然后,它通过转换f2并尝试将其与f1匹配来执行相同的过程。最后,在经过每一对之后,编译器可以确定哪个模板候选者是最专业的。如果这样做失败,则编译将失败。
在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:
  • 转换后的(1)应用于(2):用T = T1和U = T2表示foo。它尝试与(2)匹配:推导失败
  • 应用于(1)的已转换(2):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)
    
    所有这些都可以在here - copied from @Yakk's comment Action 中看到。

    关于c++ - 如何确定功能特化的主要模板?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40284153/

    10-11 23:07
    查看更多