在头文件中使用constexpr

时间:2018-05-23 12:47:08

标签: c++ c++11 constexpr

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

 constexpr double PI=3.14;

在一个包含在几个cpp文件中的头文件中有这个问题吗?

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

我正在使用C ++ 11

3 个答案:

答案 0 :(得分:33)

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

static变量暗示const是专门为在C ++中的头文件中使用const而不是#define来定义常量而引入的。如果没有static,那么如果该头文件包含在链接在一起的多个翻译单元中,则会出现多个符号定义链接器错误。

在C ++ 17中,你也可以使它成为inline,这样只要有一个PI的副本,如果它的地址或引用(即不是static })。在C ++ 17中引入了inline个变量,以允许头文件中包含非const变量定义的头文件库。静态数据成员constexpr隐含inline,因此inline不需要{。}}。

换句话说,如果可能,您应该在头文件中使用constexpr作为常量,否则const。如果您要求该常量的地址相同,请将其标记为inline

答案 1 :(得分:5)

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

constexpr double PI () { return 3.14; }

答案 2 :(得分:1)

C ++ 17 inline变量可运行示例

在以下位置提到了

C ++ 17内联变量:use of constexpr in header file,这是一个最小的可运行示例,该示例显示仅使用了一个内存位置:

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.hpp

#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具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址。

cppreference https://en.cppreference.com/w/cpp/language/inline解释说,如果未提供static,则它具有外部链接。

另请参阅:How to declare constexpr extern?

在GCC 7.4.0,Ubuntu 18.04中进行了测试。

C ++ 20 std::math::pi

请注意,对于Pi的特定情况,C ++ 20提供了专用的变量模板,如下所示:How to use the PI constant in C++