【发布时间】:2019-02-22 22:27:25
【问题描述】:
在我阅读了这个question 的答案后,我仍在提问。答案涉及 [temp.point] 中定义的实例化点的位置,但如果需要实例化,则不会对其进行评估。
[temp.inst]指定何时需要函数模板特化实例化,一般规则是:
实现不应隐式实例化函数模板、变量模板、成员模板、非虚拟成员函数、成员类,[...],除非需要这样的实例化。
此外,在标准本节的某些段落中,声明的实例化和定义的实例化是分开考虑的。
让我们考虑一下这段代码:
static void Yeap0(int);
template <class T>
void Yeap(T a){
Yop(a);
}
template <class T>
auto Yeap2(T a){
Yop(a);
return 0;
}
namespace x{
struct y{};
}
int main() {
Yeap0(0);//ok no definition required here
x::y ax{};
Yeap(ax); //the declaration is sufficient,
Yeap2(ax); //need to deduce auto => definition required
//compilation error
return 0;
}
namespace x{
void Yop(y){}
}
static void Yeap0(int){}
Gcc、Clang 和 MSVC 仅对 Yeap2(ax) 产生错误,抱怨在 Yeap2 的实例化点未定义 Yop。
但不会为Yeap(ax) 生成此错误。从基本考虑这似乎是合乎逻辑的,只需要声明,至于无模板函数Yeap0。
但是[temp.inst]/4的演讲让我很困惑。可以理解为Yeap的实例化也是需要的。但似乎编译器走了一条更聪明的路。
编译器的行为是扩展吗?
注意:我不会接受“无需诊断”的答案。这将是对智力的侮辱:有人能相信 3 个编译器已经特别注意关闭像 Yeap(ax) 这样的案例而不是 Yeap2(ax) 的诊断吗?
【问题讨论】:
-
可能不是“关闭诊断”。对于
Yeap2,编译器必须查看函数以确定返回类型。对于Yeap,不必如此。三个编译器在这方面表现相同是绝对合理的。 -
显然编译器开发人员不只是针对特殊情况关闭诊断。该标准将 NDR 用于不可能/很难证明的事情,有时在某些情况下诊断对编译器来说很容易,有时则不然。甚至 EDG 也有同样的行为。
-
@T.C.您应该阅读标准,编译器正在做正确的事情:
Yeadp(ax)导致重载解析参见 [expr.call],根据 [temp.inst]/9 如果函数模板或成员函数模板特化是以涉及重载决议的方式使用时,特化的声明被隐式实例化。 this 实例化在实例化点执行 [temp.point] 指定实例化点在哪里:在 main 之后,它没有说明实例化什么或是否需要实例化。
标签: c++ templates language-lawyer instantiation