头文件中的内联函数可以使用具有内部链接的常量吗?

Can an inline function in a header file use a constant which has internal linkage?

考虑以下代码:

const int a = 0;
const std::string b = "hi";

inline void f_a1()
{
    std::cout << a;
}

inline void f_b1()
{
    std::cout << b;
}

inline void f_a2()
{
    std::cout << &a;
}

inline void f_b2()
{
    std::cout << &b;
}

假设此代码存在于将包含在多个翻译单元中的头文件中。

我对内联函数的理解是它们在每个翻译单元中必须完全相同。

我对上面使用的常量的理解是,它们是隐含的 static 即内部链接。这意味着每个翻译单元都有自己的副本。

由于上面的内联函数依赖于这些常量,这些函数中哪些是正确的?

如果包含在多个翻译单元中,则唯一有效的函数是 f_a1

相关子句是[basic.def.odr]/6,它声明一个inline函数可以出现在多个翻译单元中,但前提是:

[...] a name can refer to a non-volatile const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.19), and the object is not odr-used, and the object has the same value in all definitions of D;

由于对象是 const,它们具有每个 [basic.link]/3:

的内部链接

A name having namespace scope (3.3.6) has internal linkage if it is the name of [...]
— a non-volatile variable that is explicitly declared const or constexpr and neither explicitly declared extern nor previously declared to have external linkage [...]

但是,获取变量的地址或形成对变量的引用(例如用于参数传递)是 odr-use,因此 f_a2f_b2 无效。 f_b1 也是无效的,因为 std::stringostream 输出运算符通过引用获取其参数;即使它按值获取参数,隐式调用的复制构造函数也会按引用获取 its 参数。 f_a1 可以,因为 int 流出运算符按值获取其参数,并且复制 int const 的值不是 odr-use。