C++ 函数模板重载:空括号与显式 int

C++ function template overload: empty braces vs explicit int

下面有一些非常基本的 C++ 函数模板重载解决方案示例(从实际代码中最小化)

struct S {
    S() {}
    S(int) {}
};

template <typename T = S>
void foo(T x) { std::cout << "S" << std::endl; }

template <>
void foo<S>(S x) { std::cout << "S spc" << std::endl; }

int main() {
    foo({});
    foo(0);
}

这里有两种情况。在第一种情况下,编译器应默认初始化某些东西(如 S),在第二种情况下将 int 转换为某些东西(如 S)

Live example on godbolt

我相信在这两种情况下,专业化都会赢得重载,因为专业化完全匹配并且通过部分排序确实比主模板更专业 [temp.deduct.partial]

但是本例中的 clang 11 和 gcc 10.2 都同意在第二种情况下主模板获胜。这个错误是在两个编译器中还是(可能)我不了解 C++ 标准?

只有一个候选人参与过载决议:

template <typename T=S> void foo(T);

函数模板特化的选择发生在之后。在这种情况下,我们有:

  • foo({}) 无法推导出 T(因为 {} 没有类型),所以我们转而使用 [=12 的默认参数=],也就是 S。这给了我们一个可行的候选人来调用 - foo<S>.

    一旦我们决定调用 foo<S>,我们就会考虑专业化。有一个,所以选择它。这打印 "S spc"

  • foo(0) 可以推导出TTint。这给了我们一个可行的候选人来调用 - foo<int>。这个没有专门化,这个[误导性]打印"S"(即使这里没有涉及S)。

只有当实际模板参数无法推导或未明确提供时,默认模板参数才会起作用。

如果你连foo(0)都想调用foo<S>,你需要防止deduction成功pick int。但在那个时候,为什么还要有一个模板,只有一个接受 S.

的函数