注意:我已经看过here了,我认为答案是对的。
在获取地址时隐式实例化功能的规则有哪些? 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 tested here会抱怨1,3和4.因此,如果它们存在,它将实例化所有定义。
VC 2010(没有在线测试,抱歉)实例化3和4,但没有实例化1。
Clang 3.0 tested here与VC 2010具有相同的行为。
没有编译器抱怨2或5,我期望。如果我实际使用了这些指针,我希望它无法链接。
在所有编译器上,6个编译。我期待这一点,但它旨在表明整个类模板没有实例化(正如在另一个问题的答案中所声称的那样),因为我采用了单个函数的地址。如果整个模板被实例化,那么S :: CallOrange不应该编译,因为B不包含Orange函数。
所以我想知道是否有人对于正确的行为应该是什么有明确的答案。该标准似乎声称不应该实例化任何函数,但在某些情况下,三个流行的编译器会实例化,但也会有所不同。
答案 0 :(得分:6)
获取其地址(在评估的上下文中)所需的函数定义。
当然,定义可以在单独的翻译单元中给出,但这并不会改变需要定义的事实。
如果只需要一个成员函数,那并不意味着其他成员函数也被实例化。
如果函数模板未定义,则无法隐式实例化。然后必须在另一个翻译单元中明确地实例化它。不允许依赖另一个翻译单元中的隐式实例化(但不需要诊断)。
答案 1 :(得分:0)
实例化需要发生,因为模板的扩展可能不会产生良好的代码。
实际上,实例化可能甚至不会产生有效的原型(这种失败会被称为'非失败')。
(当涉及SFINAE时,在选择实际候选人获取地址之前,所采用的有效地址可能会忽略部分排序中的几个先前候选人(因为替换失败不是错误)。