首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >方法的静态函数的等价性

方法的静态函数的等价性
EN

Stack Overflow用户
提问于 2019-01-03 23:58:34
回答 2查看 0关注 0票数 0

有时,我想在头文件中包含一个函数(包含在多个不同的转换单元中),而不告诉编译器内联它(例如在一个只有头的库中)。这样做很容易做C风格的方式,只需声明函数static,例如:

   struct somedata { ... }

   static somefunc (somedata *self) { ... }

这使得编译器可以决定是否内联函数,同时仍然允许多个翻译单元中的函数的多个定义,因为它没有外部链接。并且还允许我使用somedata在其他翻译单元中创建的结构调用此函数,因为类型是兼容的。

我的问题是,如何使用类和方法执行此操作?例如,使用此头文件,使用类和方法而不是函数和显式对象指针实际上是相同的事情:

   struct someclass {
      void method ();
   }

   void someclass::method () { ... }

显然,我不能使用,static someclass::method因为这完全是另一回事。

我也不能将它放入一个匿名命名空间,因为我struct someclass在不同的翻译单元中得到不同的类型,即我不能someclass *在另一个文件中使用一个文件,因为它们是不同的(和不兼容的)类型。

我可以声明所有这些方法inline,这些方法可行,但是会产生不良影响,即使在没有意义的情况下要求编译器内联它们。

我错过了一些明显的东西,或者C ++没有相应的static方法吗?正如我所看到的(希望是错误的),对我来说唯一的选择是将所有这些方法移动到一个单独的翻译单元中,或者将它们全部标记为内联 - 似乎没有相当于C风格的内部链接。

更新:我认为这个问题过早关闭,因为重复。所谓的重复问题是关于标记函数是否内联将始终内联它们。这个问题是关于如何避免ODR规则作为普通函数的静态关键字,或解释这不能在C ++中完成,其他问题都没有解答,这只是告诉提问者不要担心它。在我的问题中,内联仅被提及为可能(但不好)的解决方案。

更新2:多次提到内联不是函数内联请求,或者C标准仅使用内联来绕过ODR规则而不要求编译器内联函数。

这两种说法显然都是不真实的。例如,仔细阅读GCC文档或LLVM源代码可以发现广泛使用的编译器确实inline将内联函数视为内联函数。我还引用了C ++ 03,其中说(在7.1.2.2中):

[...]内联说明符向实现指示在调用点处函数体的内联替换优先于通常的函数调用机制。[...]

所以现有的编译器和C ++标准(我只检查过148882:2003)显然不同意“内联只影响ODR”的重复声明。

这种错误的看法似乎相当普遍,例如:https://blog.tartanllama.xyz/inline-hints/其中有人通过查看实际的GCC / LLVM源代码来调查此声明并发现两个编译器都将内联视为内联实际的内联请求。

但是,请记住,我的问题是如何static在C ++ 中获取成员函数的效果,或者获得更明确的声明,即C ++根本没有成员函数的此功能,仅用于普通函数。这里的属性inline仅与它确实解决问题的程度相关,而代价是可能不需要的内联,这可能对性能有害。

对我来说相对清楚的是,没有办法绕过一个定义规则。我不清楚的是,是否真的没有办法实现这种效果。例如,下一个最好的东西static是匿名命名空间,但这也不起作用,因为它使得在其中声明的结构在不同的转换单元之间都不兼容,因此它们不能互换。

我希望可能有一种解决方法,例如,通过将结构放在匿名命名空间之外并在内部有一个派生类,或者其他一些构造,但我现在看不出如何,同时我不能排除它可能 - 因此这个问题。

更新3:为了澄清示例 - 方法不包含静态变量,只要所有此类副本的行为相同,最终结果是否会导致方法的多个物理上不同的副本无关紧要。这种方法的一个实际例子是:

char *reserve (int bytes)
{
  if (left <= bytes)
    flush ();

  if (left <= bytes)
    throw std::runtime_error ("bulkbuf allocation overflow");

  return cur;
}

如果经常调用此方法(在源代码中),但不经常调用(在运行时),请求编译器无缘无故地内联它可能对性能和代码大小产生不利影响。

EN

回答 2

Stack Overflow用户

发布于 2019-01-04 08:00:11

标记inline

如果您标记该功能,static您将在包含该标题的每个翻译单元中获得该功能的单独副本; 因此,您将在可执行文件中拥有该功能的多个副本。如果你标记它inline并且编译器没有内联展开它,你将在可执行文件中获得它的一个副本,无论有多少翻译单元包含该标题。

票数 0
EN

Stack Overflow用户

发布于 2019-01-04 09:27:16

非成员函数的语义staticinline非成员函数的语义是不同的,即使函数定义在其他方面是相同的。

// in several translation units
static void foo_static() { 
   static int bar; // one copy per translation unit
}

// in several translation units
inline void foo_inline() { 
   static int bar; // one copy in the entire program
}

&foo_static翻译单位也会有所不同,但&foo_inline同样如此。

static为成员函数请求语义(即使对于静态成员函数)。

inline如果没有实际声明它(显式或隐式),也无法为任何函数请求语义inline。换句话说,没有办法说“使这个函数inline在除了实际内联之外的所有内容中表现得像”。

另一方面,函数模板的语义类似于inline没有向编译器请求的函数(现在无论如何都没有意义)在其调用站点内联它们。

// in several translation units
template <nullptr_t=nullptr>
void foo_template() { 
   static int bar; // one copy in the entire program
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100005148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档