我可以在类头文件中定义一个类的const静态实例吗

Can I define a const static instance of a class in the class header file

本文关键字:一个 const 静态 实例 文件 定义 我可以      更新时间:2023-10-16

是否可以在类头文件中声明和定义类的const静态实例。

我想做这样的事情(从这个类似的问题):

class PlaceID {
public:
inline PlaceID(const std::string placeName):mPlaceName(placeName) {}
const static PlaceID OUTSIDE;
private:
std::string mPlaceName;
};
const PlaceID PlaceID::OUTSIDE = PlaceID("");

如果PlaceID::OUTSIDE的定义在源文件中,这将起作用,但如果它在包含在多个位置的头文件中,则会导致链接错误,因为PlaceID::UTSIDE随后被定义了多次。

出于两个原因,我想在头文件中定义它。首先,这将是一个库的一部分,我希望这个库只是头文件。

第二,这是我希望编译器能够"内联"这个实例的使用的最重要的一个。有问题的类(不是这里用作示例的类)是基元类型的包装器,所有方法都内联,以便提供与基元类型相同的性能。如果我把这个实例的定义放在源文件中,编译器在编译时将不知道它的值,也无法应用一些优化。

谢谢。

在C++17中,变量可以标记为inline:

class PlaceID 
{
inline const static PlaceID OUTSIDE{""};
// ...
};

在C++14之前,您可以使用一个函数:

class PlaceID 
{
static PlaceID OUTSIDE() { return PlaceID{""}; }
// ...
};

class PlaceID 
{
static PlaceID OUTSIDE() 
{ 
static PlaceID result{""};
return result;
}
// ...
};

取决于是否需要单个PlaceID实例。


或者,您可以在伪参数上模板化PlaceID,以便在标头中内联OUTSIDE的定义:

template <typename>
struct PlaceID_
{
inline PlaceID_(const char*) { }
const static PlaceID_ OUTSIDE;
};
template <typename T>
const PlaceID_<T> PlaceID_<T>::OUTSIDE{""};
using PlaceID = PlaceID_<void>;

这是因为模板是隐式inline。请参阅内联变量如何工作?了解更多详细信息。

wandbox.org上的实时示例


如果可能的话,还可以考虑将PlaceID::PlaceID(const char*)标记为constexpr,这样OUTSIDE也可以标记为constexpr。显然,如果您决定使用std::string,这将不起作用。

包含在多个位置中的

您可以通过此(许多库常用)阻止您的头被多次包含(并导致您的问题(免责声明:我没有测试过它。)

a.hpp

#ifndef LIBRARY_A
#define LIBRARY_A
//define other things
#endif

LIBRARY_A替换为您选择的ID(请注意,它不会与其他库冲突,因此避免使用SOUND_SYSTEM之类的名称,而是使用SOUND_LIBRARY_FOOFOO替换为您的项目名称/您的姓名)