7

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

获取地址时,管理函数隐式实例化的规则是什么?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 函数。

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

4

2 回答 2

6

如果您获取其地址(在评估的上下文中),则需要定义函数。

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

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

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

于 2013-04-24T16:28:03.167 回答
0

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

事实上,实例化甚至可能不会产生有效的原型(这种失败将被视为“非失败”)。

(当涉及 SFINAE 时,在选择实际候选地址之前,所采用的有效地址可能会忽略部分排序中的几个较早的候选者(因为替换失败不是错误)。)

于 2013-04-24T15:05:13.220 回答