我的理解是,类类型的constexpr全局变量几乎不可用,因为

  • 必须在每个TU中定义这样的对象,因为constexpr不允许前向声明对象。
  • 默认链接为static会导致内联函数中的对象命名(是否使用ODR)违反ODR,因为相应的inline定义将具有不同的含义。
  • 如果对象使用ODR,则声明为每个TU一个定义的extern constexpr会违反ODR规则,这是在引用该对象时发生的。
  • 即使成员函数未使用隐式this参数,也会对其进行引用。
  • 如果您尝试通过引用传递对象,显然会发生。
  • 如果尝试按值传递对象,也会隐式使用副本或移动构造函数,该构造函数按定义通过引用传递。
  • 如果未将对象声明为extern constexpr,即使未使用ODR,GCC和Clang都提示违反ODR(多个定义)。

  • 这一切正确吗?有没有办法在不将其包装在constexpr函数中的情况下,使它具有全局类类型的inline

    最佳答案

    可以使用一些宏魔术和众所周知的额外间接级别,在 header 中安全地定义全局constexpr变量ODR

    #define PP_GLOBAL_CONSTEXPR_VARIABLE(type, var, value)                   \
    namespace var##detail {                                                  \
    template<class = void>                                                   \
    struct wrapper                                                           \
    {                                                                        \
         static constexpr type var = value;                                  \
    };                                                                       \
    template<class T>                                                        \
    constexpr type wrapper<T>::var;                                          \
    }                                                                        \
    namespace {                                                              \
    auto const& var = var##detail::wrapper<>::var;                           \
    }
    

    该宏在未命名的命名空间中提供了引用
    到实现类模板中的对象实例。

    header 中未命名空间中的每个对象都会生成
    每个翻译单元中包含其 header 的唯一实例。
    此外,为了防止违反ODR,重要的是对象
    在例如功能模板的多个实例是相同的。

    但是,对于引用而言,它们具有不同的身份并不重要;
    只要它们在实现中引用相同的对象实例
    类模板。

    您可以将此宏包装在 header 中,并可以安全地将其包含在许多TU中。

    有关更多详细信息,请参见Boost邮件列表上的以下讨论:
    http://lists.boost.org/Archives/boost/2007/06/123380.php

    关于c++ - constexpr全局类类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20370024/

    10-11 23:06