【问题标题】:Can I define a const static instance of a class in the class header file我可以在类头文件中定义一个类的 const 静态实例吗
【发布时间】:2017-11-13 13:19:25
【问题描述】:

是否可以在类头文件中声明和定义一个类的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 被定义了多次。

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

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

谢谢。

【问题讨论】:

    标签: c++


    【解决方案1】:

    在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,这将不起作用。

    【讨论】:

    • 我喜欢函数的使用。我会测试它是否“内联”它。
    • @MathieuPagé:查看更新的答案,添加了另一种技术
    • 为什么要附加 inlined 包装器? template &lt;class = void&gt; const static PlaceID OUTSIDE{""}; 不也一样吗?
    • @VittorioRomeo 呜呜,说得通。 template &lt;typename T = PlaceID&gt; const static T OUTSIDE{""}; 确实有效(前提是构造函数是 constexpr,无论如何都需要)。
    • @Quentin:我真的搞砸了,我已经用我真正想要实现的目标更新了答案
    【解决方案2】:

    包含在多个位置

    你可以阻止你的标题被多次包含(并导致你的问题(免责声明:我没有测试过。))通过这个(很多库常用)

    a.hpp

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

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

    【讨论】:

      猜你喜欢
      • 2012-10-24
      • 2010-10-31
      • 1970-01-01
      • 2010-12-07
      • 2019-05-05
      • 2013-08-20
      相关资源
      最近更新 更多