获取函数模板的地址时隐式实例化

Implicit instantiation of function templates when taking their address

本文关键字:实例化 地址 函数模板 获取      更新时间:2023-10-16

注意:我已经看了这里,我不认为答案是正确的。

在获取地址时,控制函数隐式实例化的规则是什么?14.7.1/9的n3242这样说:

实现不应隐式实例化不需要实例化的函数模板、成员模板、非虚成员函数、成员类或类模板的静态数据成员。

现在,当然不需要有一个函数定义来获取它的地址。我们可以采用前向声明函数的地址,并将它们定义在不同的翻译单元中。

既然如此,我不知道什么时候需要。然而,编译器似乎有自己的想法。在GCC和VC上测试,这里有几个例子:

template <typename T> void CallBanana() { T::Banana(); }
template <typename T> void CallUnimpl();
template <typename T>
struct S {
    static void CallBanana() { T::Banana(); }
    static void CallOrange() { T::Orange(); }
    static void CallUnimpl();
};
struct B { static void Banana() {} };
int main() {
    (void)(&CallBanana<void>); // 1
    (void)(&CallUnimpl<void>); // 2
    (void)(&S<void>::CallBanana); // 3
    (void)(&S<void>::CallOrange); // 4
    (void)(&S<void>::CallUnimpl); // 5
    (void)(&S<B>::CallBanana); // 6
}

应该一次注释一个,以查看效果。

这里测试的

GCC 4.7会报错1、3和4。因此,它将实例化所有存在的定义。

VC 2010(没有在线测试,抱歉)实例化了3和4,但没有实例化1。

Clang 3.0在这里测试的行为与VC 2010相同。

没有编译器抱怨2或5,这是我所期望的。如果我真的使用了这些指针,我希望它链接失败。

在所有编译器上,6个编译器。我预料到这一点,但它的目的是表明,仅仅因为我取了单个函数的地址,整个类模板就没有被实例化(正如在另一个问题的答案中所声称的那样)。如果整个模板都被实例化了,那么S::CallOrange不应该被编译,因为B不包含Orange函数。

所以我想知道是否有人有一个明确的答案,正确的行为应该是什么。标准似乎声称不应该实例化函数,然而三种流行的编译器在某些情况下实例化,但彼此也不同。

如果取函数的地址(在求值的上下文中),则需要函数的定义

当然,定义可以在单独的翻译单元中给出,但这并不能改变需要定义的事实。

如果只需要一个成员函数,并不意味着也要实例化其他成员函数。

如果函数模板未定义,则不能隐式实例化。然后必须在另一个翻译单元中显式地实例化它。不允许依赖于另一个翻译单元中的隐式实例化(但不需要诊断)。

需要进行实例化,因为扩展模板可能无法生成格式良好的代码。

事实上,实例化甚至可能不会产生一个有效的原型(这种失败将被限定为"不失败")。

(当涉及到SFINAE时,所取的有效地址可能会在部分排序中忽略几个较早的候选者(因为替代失败不是错误),然后才选择实际候选者来取。的地址)