我应该何时inline在C++中为函数/方法编写关键字?
看到一些答案,一些相关的问题:
我应该何时不写在C++函数/方法关键字"内联"?
什么时候编译器不知道何时使函数/方法'内联'?
当一个应用程序为函数/方法写入"内联"时,是否多线程是否重要?
我是使用SSE/SSE2指令优化代码的新手,直到现在我还没有走得太远.据我所知,一个常见的SSE优化函数如下所示:
void sse_func(const float* const ptr, int len){
if( ptr is aligned )
{
for( ... ){
// unroll loop by 4 or 2 elements
}
for( ....){
// handle the rest
// (non-optimized code)
}
} else {
for( ....){
// regular C code to handle non-aligned memory
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如何正确确定内存ptr点是否与16字节对齐?我认为我必须包含非对齐内存的常规C代码路径,因为我无法确保传递给此函数的每个内存都将对齐.使用内在函数将数据从未对齐的内存加载到SSE寄存器似乎非常慢(甚至比常规C代码慢).
先感谢您...
inline如果它们包含在多个cpp文件中,我是否需要模板功能?谢谢.
template<bool> inline QString GetText();
template<> inline QString GetText<true>() {return "true";}
template<> inline QString GetText<false>() {return "false";}
Run Code Online (Sandbox Code Playgroud) 我已经了解了通常最好不要在头文件中定义任何内容,因为冗余副本是针对包含头文件的每个其他文件进行的.但是,在静态内联方法的情况下,似乎我必须在现场定义它(至少Visual Studio 2010不允许我这样做).因此,如果我在头文件中编写接口,我就无法定义类定义的静态内联方法或.cpp文件.
那么,我是否应该费心去使用静态内联方法呢?还有一个相关的问题:我是否应该在头文件中定义任何方法或变量(常量怎么样)?
无论如何,奇怪的是,这不是我的C++书籍中非常详细的内容.
编辑:我读过有关静态内联方法的类似问题,但似乎没有一个直接解决这个问题.
看看这个假设的头文件:
template <class T>
class HungryHippo {
public:
void ingest(const T& object);
private:
...
}
Run Code Online (Sandbox Code Playgroud)
现在,因为HungryHippo<string>你想要ingest引用字符串是有意义的 - 复制字符串可能非常昂贵!但对于HungryHippo<int>它来说,它没那么有道理.int直接传递可能非常便宜(大多数编译器会在寄存器中执行),但是传递对a的引用int是一个额外的不必要的间接级别.这一切都适用于返回值.
有没有办法向编译器建议"嘿,我不会修改参数,所以你决定是通过值还是通过引用来传递,这取决于你认为哪个更好"?
一些可能相关的事情:
template <class T, bool PassByValue> class HungryHippo然后专注来手动伪造这种效果PassByValue.如果我想得到真正的幻想,我甚至可以PassByValue根据sizeof(T)和推断std::is_trivially_copyable<T>.无论哪种方式,当实现看起来几乎相同时,这是一项额外的工作,我怀疑编译器可以更好地决定是否通过值传递.ingest是相当复杂的,不值得内联.inline默认情况下所有模板函数都是如此.c++ compiler-construction performance pass-by-value pass-by-const-reference
可以在其体外定义类模板的虚函数吗?虚函数不能内联,但为了避免编译单元中的多个定义,应标记它们inline(假设模板头将包含在多个源文件中).另一方面,编译器可以自由忽略inline,因此这似乎是有效的.举个例子,下面的代码是正确的:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
Run Code Online (Sandbox Code Playgroud)
?
BTW gcc(3.4.2)允许inline在定义函数f(T val)之前省略,但不能在常规类的类似函数之前省略.这只是gcc的行为吗?
我有一个带有特化的模板类,在另一个文件中定义.因此,可以生成同一类的两个版本:一次通过替换模板参数,一次使用专门化.我目前的理解是,这可能导致同一类型的两个实例在内存中具有不同的大小,从而导致分段错误.
我创建了一个最小的示例,以下代码用于说明问题:
创建模板类:
// - templateexample.h ---------------
#ifndef TEMPLATEEXAMPLE_H
#define TEMPLATEEXAMPLE_H
template<typename T> class Example
{
public:
Example(){}
int doWork() {return 42;}
};
#endif
// -----------------------------------
Run Code Online (Sandbox Code Playgroud)
另一个文件中的模板特化:
// - templatespecialization.h --------
#ifndef TEMPLATESPECIALIZATION_H
#define TEMPLATESPECIALIZATION_H
#include "templateexample.h"
template<> class Example<int>
{
public:
Example() : a(0), b(1), c(2), d(3) {}
int doWork() {return a+b+c+d;}
private:
int a; //<== the specialized object will be larger in memory
int b;
int c;
int d;
};
#endif
// --------------------------------
Run Code Online (Sandbox Code Playgroud)
有一个只包含模板类定义的类,但应该包含特化.
// - …Run Code Online (Sandbox Code Playgroud) 我正在维护一个大型的模板类库,它们可以根据任何一个float或double类型执行代数计算.许多类都有访问器方法(getter和setter)以及运行少量代码的其他函数,因此当编译器定位它们的定义时,需要将这些函数限定为内联.相反,其他成员函数包含复杂的代码,因此最好调用而不是内联.
函数定义的很大一部分位于头文件中,实际上是头文件所包含的.inl文件.但也有很多类,其功能定义,幸福地生活在.cpp文件通过显式实例化的手段float和double,这是相当的好东西在图书馆的情况下做的(这里解释为什么).最后,有相当多的类,它们的函数定义被分解为.inl文件(访问器方法)和.cpp文件(构造函数,析构函数和繁重的计算),这使得它们都很难维护.
只有当我知道一种可靠的方法来防止某些函数被内联时,或者在.cpp文件中,如果inline关键字可以强烈建议编译器内联一些函数,我当然会在.inl文件中实现所有类实现,当然,它才不是.我真的更喜欢库中的所有函数定义都驻留在.cpp文件中,但由于访问器方法在整个库中被广泛使用,所以我必须确保它们在被引用时被内联,而不是被调用.
所以,在这方面,我的问题是:
inline考虑到这样一个事实,标记模板函数的定义是否有意义,正如我最近在这里学到的那样,它将被编译器自动限定为内联,无论它是否标记inline?
而最重要的,因为我想有聚集了模板类的所有成员函数的定义在一个文件一起,要么(使用显式实例中的.cpp的情况下),最好是.INL或的.cpp 仍然能够提示编译器(MSVC和GCC)应该内联哪些函数,哪些不应该,确定模板函数是否可以实现,如何实现这一点,或者如果真的没有办法(我希望有的话) ),最佳折衷方案是什么?
EDIT1:我知道inline关键字只是建议编译器内联函数.
EDIT2:我真的知道.我喜欢向编译器提出建议.
EDIT3:我还是知道.这不是问题所在.
鉴于一些新的信息,还有第三个问题与第二个问题密切相关.
3.如果编译器如此聪明,以至于他们可以更好地选择应该内联哪个函数以及应该调用哪个函数,并且能够进行链接时代码生成和链接时优化,这有效地允许他们查看.cpp -located函数定义在链接时决定其内联或调用的命运,那么一个好的解决方案可能只是将所有定义移动到相应的.cpp文件中?
那么结论是什么?
首先,我很感谢Daniel Trebbien和Jonathan Wakely的结构和有根据的答案.投票两者但必须只选择一个.然而,给出的答案都没有给我一个可接受的解决方案,所以所选择的答案恰好是帮助我做出最终决定的其他答案,其中的细节将在下一个对任何感兴趣的人解释.
好吧,因为我一直在重视代码的性能而不是维护和开发的方便性,在我看来,最可接受的折衷方案是移动所有的访问器方法和其他每个的轻量级成员函数.将模板类放入相应标头所包含的.inl文件中,用inline关键字标记这些函数,以试图为编译器提供良好的提示(或使用关键字进行内联强制),并将其余的函数移动到相应的.cpp文件.
将所有成员函数定义放在.cpp文件中会妨碍内容轻量级函数,同时释放链接时优化的一些问题,正如Daniel Trebbien为MSVC(在较旧的开发阶段)和Jonathan Wakely为GCC所确定的那样(在目前的发展阶段).并且将所有函数定义放在头文件(或.inl文件)中并不会超过将每个类的实现分类为.inl和.cpp文件以及此决策的额外副作用的总体好处:它将确保只有原始访问器方法的代码对于库的客户端是可见的,而更复杂的东西隐藏在二进制文件中(确保这不是一个主要原因,但是这对于熟悉软件库的人来说是显而易见的. ).并且任何不需要通过库的包含文件公开并且由其类私有使用的轻量级成员函数可以在类的.cpp文件中定义,而其声明/定义inline用于鼓励函数的内联状态(在这个特定情况下,不知道关键字是在两个地方还是只有一个).
constexpr我想为一个类提供Color如下功能:
// color.hpp
struct Color
{
Color(int r, int g, int b, int a);
static const Color Red;
// ...
};
// color.cpp
Color::Color(int r, int g, int b, int a) { /* ... */ }
const Color Color::Red(255, 0, 0, 255);
// ...
Run Code Online (Sandbox Code Playgroud)
我的愿望是保持此类的 API 不变,因此我想完全删除color.cpp并对头文件进行以下更改:
// color.hpp
struct Color
{
constexpr Color(int r, int g, int b, int a) { /* ... */ }
inline static constexpr Color Red{255, 0, 0, 255};
// …Run Code Online (Sandbox Code Playgroud) c++ ×9
inline ×4
templates ×4
static ×2
c ×1
c++-faq ×1
c++17 ×1
constexpr ×1
header-files ×1
memory ×1
optimization ×1
performance ×1
simd ×1
sse ×1
virtual ×1