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

时间:2017-11-13 13:19:26

标签: c++

是否可以在类头文件中声明和定义类的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>

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

其次,这是我希望编译器允许“内联”此实例的使用的最重要的一个。有问题的类(不是这里用作示例的类)是基本类型的包装器,所有方法都是内联的,以便提供与基本类型相同的性能。如果我将此实例的定义放在源文件中,编译器将不会在编译时知道它的值,并且无法应用某些优化。

感谢。

1 个答案:

答案 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?

live example on wandbox.org

如果可能,请考虑将PlaceID::PlaceID(const char*)标记为constexpr,以便OUTSIDE也可以标记为constexpr。显然,如果您决定使用std::string,这将无效。