是否可以在类头文件中声明和定义类的const静态实例。
我想做这样的事情(来自this类似的问题):
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 :: OUTSIDE会被多次定义。< / p>
我想在头文件中定义它有两个原因。首先,这将是库的一部分,我希望库只是头文件。
其次,这是我希望编译器允许“内联”此实例的使用的最重要的一个。有问题的类(不是这里用作示例的类)是基本类型的包装器,所有方法都是内联的,以便提供与基本类型相同的性能。如果我将此实例的定义放在源文件中,编译器将不会在编译时知道它的值,并且无法应用某些优化。
感谢。
答案 0 :(得分:6)
在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
。有关详细信息,请参阅How do inline variables work?。
如果可能,请考虑将PlaceID::PlaceID(const char*)
标记为constexpr
,以便OUTSIDE
也可以标记为constexpr
。显然,如果您决定使用std::string
,这将无效。