在以下示例中,如果您将 更改auto为 ,void程序将打印1而不是0。为什么会发生这种情况。这里适用哪些查找规则?

#include <iostream>

struct X { operator int() const; };

std::false_type f(int);

template <typename T>
auto f2(T t) {
    std::cout << decltype(f(t)){};
}

decltype(f2(X{}))*_;

std::true_type f(X);


int main() {
    f2(X{});
}

1

  • 3
    decltype(f2(X{}))可能需要实例化f2<X>才能知道返回类型(顺便说一下,在(in )f2<X>之后会有另一个含义,所以格式不正确的 NDR)…std::true_type f(X);main


    – 



最佳答案
1

void在和之间切换返回类型auto会改变是否decltype(f2(X{}))执行的隐式实例化f2

当返回类型拼写为 时void,声明就足够了;定义不需要实例化。然后f2<X>有一个实例化点 – 在翻译单元的末尾,紧接着main。此时, 的两个重载f可见,并且f(X)被选为更好的匹配。

当返回类型为 时auto,定义需要实例化。然后f2<X>有两个实例化点 – 一个在 之后main,另一个在行上decltype。现在,不同的实例化点赋予模板特化不同的含义,此时程序格式不正确,无需诊断。显然,您的实现恰好选择了第一个实例化点,其中只有一个f重载可见。


[temp.point]/1对于函数模板专业化…这种专业化的实例化点紧跟引用该专业化的命名空间范围声明或定义。

[temp.point]/8函数模板的特化…可能在一个翻译单元内有多个实例化点,除了上面描述的实例化点之外,对于任何在翻译单元内有实例化点的特化,翻译单元的末尾也被视为实例化点…如果两个不同的实例化点根据单一定义规则(6.2)赋予模板特化不同的含义,则程序格式不正确,无需进行诊断。