注意:我已经看过这里,我认为答案不正确。
获取地址时,管理函数隐式实例化的规则是什么?n3242 的 14.7.1/9 说:
实现不应隐式实例化不需要实例化的类模板的函数模板、成员模板、非虚拟成员函数、成员类或静态数据成员。
现在,当然不需要有一个函数定义来获取它的地址。我们可以获取前向声明函数的地址,并将它们定义在不同的翻译单元中。
既然如此,我不知道什么时候需要。然而,编译器似乎有自己的想法。在 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 函数。
所以我想知道是否有人对正确的行为应该是什么有明确的答案。该标准似乎声称不应实例化任何函数,但三个流行的编译器在某些情况下会实例化,但也彼此不同。