在模板特化的情况下,编译器是否允许忽略内联?

时间:2009-11-19 01:10:04

标签: c++ templates compiler-construction

假设你有简单的模板函数(为了简单起见不是类成员),在同一个.h文件中具有特定于类型的特殊化...

template <class TYPE>
void    some_function(TYPE& val)
{
    // some generic implementation
}

template <>
inline void some_function<int>(int& val)
{
    // some int specific implementation
}

除非您明确地将编译器指向inline特化(inline关键字),否则如果.h文件被包含多次,则会出现链接错误(至少我在Visual C ++ 2008中)。
我们都知道inline只是对编译器的建议,它可以忽略。在这种特殊情况下,编译器是否允许忽略此建议并让链接器失败?

5 个答案:

答案 0 :(得分:7)

如果不使用inline,则相同的函数会使用extern链接编译成多个.obj文件,这会导致链接器抛出重复的符号错误。

这与编译器实际是否内联编译函数无关,因为它可以将它视为static函数,并使每个实现对每个编译单元都是私有的。但是,您不能将static用于此目的,因为它对成员函数有其他意义,因此inline是您唯一的选择。

答案 1 :(得分:5)

您误解了经常提到的“忽略内联”可能性的含义。

永远不允许编译器忽略函数声明中使用的inline说明符以及此说明符对单一定义规则(ODR)的影响。

当有人说允许编译器“忽略内联”时,它只意味着编译器不需要实际内联调用到相关函数。 “忽略内联”意味着生成对内联函数的普通(非内联)函数调用。

在任何情况下,即使编译器决定始终生成对内联函数的普通调用(即始终“忽略内联”),仍然需要将该函数视为内联以用于ODR。编译器如何做到这一点是编译器的问题。你不应该担心它。

在原始示例中,您不应该收到任何链接器错误。

答案 2 :(得分:1)

这是由标准定义的,并且编译器在这方面完全符合它的外观。你正在追求的是联系。隐式模板实例化具有“特殊”链接,如内联函数所做的那样。还有一个static(关键字),它已被弃用,有利于匿名命名空间:

namespace {
    …declarations…
}

所以是的,这个专业化(在你的例子中)具有与:

相同的链接
void some_other_function(int& val) {
    // some int specific implementation
}

事实上,在你的例子中,编译器可能会混淆内联专业化,并说它们不匹配。因此,最好将它们标记为内联(或其他方式)。

答案 3 :(得分:0)

我相信你可以明确地将方法声明为extern,然后将特化放入.cpp。我曾经尝试过与GCC过去类似的东西,但我不记得它是如何工作的具体细节。 MSDN Magazine has an article on this可能有所帮助。

答案 4 :(得分:0)

您实际看到的是单定义规则(ODR)具有内联函数的特殊情况,因为每个TU可能都有一个定义。如果函数(例如显式int特化)不是内联的,那么在链接时会出现多个定义错误。这种内联函数仍然具有外部链接。功能模板是模板,因此遵循不同的规则。功能模板的实例化/特化是功能

对于任何函数来说,使用内联只是一个提示,但是如果函数很短(对于任何函数)或者你只想将它保留在头文件中,你可能想要应用它。这是一个没有内联的例子:

标题文件:

template<class TYPE>
void some_function(TYPE& val) {
  // some generic implementation
}

template<>
void some_function<int>(int& val);

实施(.cpp)文件:

template<>
void some_function<int>(int& val) {
  // some int specific implementation
}