代码之家  ›  专栏  ›  技术社区  ›  mans

在头文件中使用constexpr

  •  20
  • mans  · 技术社区  · 6 年前

    我可以在头文件中有这样的定义吗?

     constexpr double PI=3.14;
    

    在包含在多个cpp文件中的头文件中是否有问题?

    我担心,因为它在标准中说这个constexpr有自己的内存,把它放在header中,并将header添加到几个cpp文件中,会在内存中生成相同值的多个副本,以及其他一些严重的问题。

    我用C++ 11

    3 回复  |  直到 6 年前
        1
  •  45
  •   Maxim Egorushkin    6 年前

    constexpr const 在全局/命名空间范围内暗示 static (内部链接),这意味着每个翻译单元(包括此标头)都会获得自己的 PI . 只有当一个地址或对它的引用被获取时,该静态内存才会被分配,并且每个翻译单元中的地址都会不同。

    这意味着 静止的 对于 常量 变量是专门为使用而引入的 警察 而不是 #define 在C++中的头文件中定义常量。没有 静止的 会有 多个符号定义 链接器错误,如果头文件包含在多个链接在一起的翻译单元中。

    inline ,所以只有一个副本 如果地址或引用被采纳(即 静止的 ). 在C++ 17中引入变量以允许头文件中具有非const变量定义的头文件库。 关于静态数据成员暗示 ,所以 内联 在那里是不必要的。

    换句话说,你应该使用 常量 .

        2
  •  8
  •   KevinZ    6 年前

    C++17 你很清楚。在 C++11 ,可以将其包装在函数中:

    constexpr double PI () { return 3.14; }
    
        3
  •  4
  •   Ciro Santilli OurBigBook.com    5 年前

    C++ 17 inline

    use of constexpr in header file

    主.cpp

    #include <cassert>
    
    #include "notmain.hpp"
    
    int main() {
        // Both files see the same memory address.
        assert(&notmain_i == notmain_func());
        assert(notmain_i == 42);
    }
    

    #ifndef NOTMAIN_HPP
    #define NOTMAIN_HPP
    
    inline constexpr int notmain_i = 42;
    
    const int* notmain_func();
    
    #endif
    

    notmain.cpp

    #include "notmain.hpp"
    
    const int* notmain_func() {
        return &notmain_i;
    }
    

    g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
    g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
    g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
    ./main
    

    GitHub upstream .

    C++标准保证地址相同。 C++17 N4659 standard draft 10.1.6“内联说明符”:

    6具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址。

    https://en.cppreference.com/w/cpp/language/inline 解释说如果 static

    另请参见: How to declare constexpr extern?

    在gcc7.4.0,ubuntu18.04中测试。

    C++ 20 std::math::pi

    How to use the PI constant in C++

        4
  •  1
  •   KPCT    6 年前

    constexpr 中的变量(int、double等)不占用内存,因此它没有内存地址,编译器会像这样处理它 #define ,它用值替换变量。但对于对象,这是不正确的,这是完全不同的。阅读 this :

    常量表达式 常量表达式 ab.h

    constexpr double PI = 3.14;
    

    你也有 a.cpp

    std::cout << PI << "\n";
    

    b.cpp :

    double *MY_PI = &PI;
    

    内存将专门为该实例分配(或者可能为整个实例) 文件)。

    编辑:

    编辑2: constExpr.h 包含以下内容:

    #ifndef CONSTEXPR_H
    #define CONSTEXPR_H
    
    #include <iostream>
    
    constexpr int a = 5;
    void bb ();
    void cc ();
    
    #endif
    

    a、 cpp公司 包含以下内容:

    #include <iostream>
    #include "constExpr.h"
    
    void aa () {
        std::cout << &a << "\n";
    }
    
    int main () {
        aa ();
        bb ();
        cc ();
        return 0;                                                                                                                 
    }
    

    包含以下内容:

    #include "constExpr.h"
    
    void bb () {
        std::cout << &a << "\n";
    }
    
    void cc () {                                                                                                  
        std::cout << &a << "\n";
    }
    

    输出为:

    0x400930
    0x400928
    0x400928
    

    常量表达式 #定义 #定义 由于编译器无法检查,因此很难调试 #定义 错误陈述。所以除非你做了上面的事情 #定义 但它是在编译时处理的,而不是由预编译程序处理的。