【发布时间】:2013-04-24 14:56:32
【问题描述】:
注意:我已经看过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 函数。
所以我想知道是否有人对正确的行为应该是什么有明确的答案。该标准似乎声称不应实例化任何函数,但三个流行的编译器在某些情况下会实例化,但彼此也有所不同。
【问题讨论】:
-
我完全不同意,据我所知,标准要求在获取地址并获取所有 6 个地址时实例化该函数。如果无法实例化函数(1、3 和 4),则会引发编译错误。所以我会说应该实例化 2、5 和 6;并且由于他们的地址被占用(您是否转换为
void无关紧要)他们的缺席应该会引发链接器错误(除非经过优化)。 -
'据我所知' - 在哪里?部分和段落,请。强制转换为 void 只是为了避免关于表达式被用作语句的警告,与我正在做的事情无关。
-
如果我有部分和段落,这将是一个答案;)我相信它属于 odr-used case。
标签: c++ templates language-lawyer