gpt4 book ai didi

c++ - 在多个模块中共享的 constexpr 函数

转载 作者:行者123 更新时间:2023-12-05 01:24:40 25 4
gpt4 key购买 nike

我在使用 constexpr 函数时注意到一个奇怪的行为。我将代码简化为一个简化的示例。从两个不同的翻译单元(模块 A 和 B)调用两个函数。

#include <iostream>

int mod_a();
int mod_b();

int main()
{
std::cout << "mod_a(): " << mod_a() << "\n";
std::cout << "mod_b(): " << mod_b() << "\n";
std::cout << std::endl;
return 0;
}

模块看起来很相似。这是 mod_a.cpp:

constexpr int X = 3;
constexpr int Y = 4;

#include "common.h"

int mod_a()
{
return get_product();
}

只有一些内部常量不同。这是 mod_b.cpp:

constexpr int X = 6;
constexpr int Y = 7;

#include "common.h"

int mod_b()
{
return get_product();
}

两个模块都使用一个共同的 constexpr 函数,该函数在“common.h”中定义:

/* static */ constexpr int get_product()
{
return X * Y;
}

两个函数都返回 12,这让我感到非常惊讶。由于 #include 指令(应该只是一些源代码包含),我认为两个模块之间没有交互。当我将 get_product 也定义为 static 时,行为符合预期:mod_a() 返回 12,mod_b() 返回 42。

我还看了 Jason Turner 的《C++ 周刊》第 312 集:停止使用“constexpr”(改用这​​个!)在 https://www.youtube.com/watch?v=4pKtPWcl1Go .

通常使用 static constexpr 的建议是一个很好的提示。

但我仍然想知道我在没有 static 关键字的情况下注意到的行为是否定义明确。还是UB?还是编译器错误?

我还尝试了 C 风格的宏 #define get_product() (X*Y) 而不是 constexpr 函数,它也显示了预期的结果(12 和42).

保重

迈克尔

最佳答案

此程序格式错误:XY 具有内部链接,因为它们是命名空间范围内的 const 变量。这意味着 constexpr int get_product() 的两个定义(隐含地 inline)都违反了 one definition rule :

There can be more than one definition in a program of each of the following: [...], inline function, [...], as long as all the following is true:

  • [...]
  • name lookup from within each definition finds the same entities (after overload-resolution), except that
    • constants with internal or no linkage may refer to different objects as long as they are not odr-used and have the same values in every definition

显然这些常量具有不同的值。


发生的事情是 mod_amod_b 都在运行时调用 get_productget_product 是隐式内联的,因此选择其中一个定义,另一个被丢弃。 gcc 似乎做的是采用找到的第一个定义:

$ g++ mod_a.cpp mod_b.cpp main.cpp && ./a.out
mod_a(): 12
mod_b(): 12
$ g++ mod_b.cpp mod_a.cpp main.cpp && ./a.out
mod_a(): 42
mod_b(): 42
$ g++ -c mod_a.cpp
$ g++ -c mod_b.cpp
$ g++ mod_a.o mod_b.o main.cpp && ./a.out
mod_a(): 12
mod_b(): 12
$ g++ mod_b.o mod_a.o main.cpp && ./a.out
mod_a(): 42
mod_b(): 42

好像 get_product 不是 constexpr,因为它在运行时被调用。

但是如果您要启用优化(或强制在编译时调用 get_product(),例如 constexpr int result = get_product(); return result; ),结果正如您“预期”的那样:

$ g++ -O1 mod_a.cpp mod_b.cpp main.cpp && ./a.out
mod_a(): 12
mod_b(): 42

(虽然这仍然是 UB,正确的解决方法是使函数static)

关于c++ - 在多个模块中共享的 constexpr 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71307601/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com