有时,我希望在一个头文件中有一个函数(包含在多个不同的翻译单元中),而不要求编译器将其内联(例如在一个只包含头的库中)。这样做很容易,只需声明函数
static
例如:
struct somedata { ... }
static somefunc (somedata *self) { ... }
这允许编译器决定是否内联函数,同时仍然允许在多个翻译单元中对函数进行多个定义,因为它没有外部链接。还允许我用
somedata
结构是用其他翻译单位创建的,因为类型是兼容的。
我的问题是,如何使用类和方法来实现这一点?例如,以这个头文件为例,使用类和方法(而不是函数和显式对象指针)实际上是相同的事情:
struct someclass {
void method ();
}
void someclass::method () { ... }
显然,我不能用
static someclass::method
因为这完全是另一回事。
我也不能将它放到匿名名称空间中,因为这样我会变得不同
struct someclass
不同翻译单位的类型,即我不能使用
someclass *
因为它们是不同的(和不兼容的)类型。
我可以宣布所有这些方法
inline
这是可行的,但会产生不希望的效果,好吧,即使在没有任何意义的情况下,要求编译器内联它们。
我是否漏掉了一些明显的东西,或者C++没有等价的东西吗?
静止的
对于方法?正如我所见(希望是错误的),我唯一的选择是要么将所有这些方法移动到一个单独的翻译单元中,要么将它们全部标记为内联-似乎没有与C样式内部链接等效的方法。
更新:
我认为这个问题过早地以重复的形式结束了。假设重复的问题是,将函数标记为inline是否总是inline。这个问题是关于如何避免ODR规则作为普通函数的静态关键字,或者解释这是不能在C++中完成的,这两个问题都没有被另一个问题回答,它只是告诉ASKER不要担心它。在我的问题中,inline只是作为一个可能(但不好)的解决方案提出来的。
更新2:
多次提到inline不是函数inline的请求,或者C标准只使用inline来绕过ODR规则,不要求编译器内联函数。
这两种说法显然是不真实的。例如,仔细阅读gcc文档或llvm源代码可以发现广泛使用的编译器确实考虑了
内联
作为内联函数的请求。我还引用了C++ 03,在(7.1.2.2)中表示:
[…]内联说明符向实现表明,在调用点对函数体的内联替换优先于常规函数调用机制。[…]
所以现有编译器和C++标准(我只检查1488 822003)显然不同意“内联只影响ODR”的重复请求。
这种错误的看法似乎很普遍,如图所示:
https://blog.tartanllama.xyz/inline-hints/
有人通过查看实际的gcc/llvm源代码来调查此声明,发现两个编译器都将inline视为实际的inline请求。
但是,请记住,我的问题是如何获得
静止的
对于C++中的成员函数,或者可选地得到一个更明确的声明,C++只对成员函数没有这个特性,只针对普通函数。的属性
char *reserve (int bytes)
{
if (left <= bytes)
flush ();
if (left <= bytes)
throw std::runtime_error ("bulkbuf allocation overflow");
return cur;
}
//inline
int f(int i)
{
return i < 0 ? 0 : f(i-1) + 1;
}
int main(int argc, char *[])
{
return f(5) + f(argc);
}
g++ -Os -S -o - test.C
main
movl %edi, %ecx
movl $5, %edi
call f(int)
movl %eax, %edx
movl %ecx, %edi
call f(int)
addl %edx, %eax
ret
xorl %eax, %eax
.L3:
cmpl %eax, %edi
js .L2
incl %eax
jmp .L3
.L2:
addl $6, %eax
ret
f
Do c++11-compatible compilers always ignore inline hints?