我正在尝试在 constexpr
中使用 make_tuple()
。它在全局范围内发挥作用。但它会为 static constexpr
类成员生成链接错误。
#include <iostream>
#include <tuple>
using namespace std;
class A
{
public:
static constexpr auto z = make_tuple(5, 3.0);
};
constexpr auto tp = make_tuple(6, 3.2);
int main()
{
cout << get<0>(tp) << " " << get<1>(tp) << endl; // OK
cout << get<0>(A::z) << " " << get<1>(A::z) << endl; // error: (.text+0x5a): undefined reference to `A::z'
// (.text+0x67): undefined reference to `A::z'
}
我查过here make_tuple
本身并不是 c++11
中的 constexpr
。我想这不是本例的问题。如果是的话,它将生成编译错误而不是链接错误。
我尝试按照 this answer 的建议在类外部定义 constexpr
,如下所示
class A
{
public:
static constexpr tuple<int, double> z;
};
constexpr tuple<int, double> A::z = make_tuple(5, 3.0);
但是,它会产生几个编译错误。根据 constexpr initializing static member using static function 的答案,这就是 sanse
在static constexpr
类成员中使用make_tuple
的正确方法是什么?
编译器:
g++ 4.8.4
和 clang 3.4
以及 -std=c++11
最佳答案
在 C++11/14 中,如果使用 ODR,static constexpr
变量必须在某处定义(ODR 使用的意思是“以需要它具有的方式使用”一个身份”。举个例子,取一个真正的引用或指向它们的指针。这里的 ODR 意思是“一个定义规则”,ODR-used 意思是“在要求它有一个定义的意义上使用”,我将其缩写为“有一个身份”)。
constexpr tuple<int, double> A::z;
我们已经定义了它存在的位置。这必须位于一个编译单元中。
在 C++17 中,添加了 inline
变量,并且我相信 constexpr
变量是隐式内联的。我不是 C++17 专家,但是it compiles and runs in C++1z mode没有定义,所以我的解释似乎至少正确了一半。
(内联
变量,就像内联
函数一样,最终在编译器想要的地方创建定义。内联
函数通常由当有人获取它的地址时,每个目标文件中都有一个带有特殊注释的定义,然后在链接时丢弃重复项,每个人都引用最后一个。我不知道是否内联
变量往往以相同或不同的方式实现。)
如果您想在 C++11 中解决此问题,而不必在具有硬编码模板参数的 .cpp
文件中放入某些内容,change z
to a constexpr
function当你想使用它时调用它。
正如 SergyA 所提到的,这里会触发 ODR,因为 get
返回对相关元组中某个字段的引用,并且该引用意味着该对象必须存在一个标识字段以及整个元组。
理论上,精心设计的按值返回的 value_get
可以避免这种 ODR 使用,但这取决于 tuple
的实现,因为它反过来又不能调用get
。
关于c++ - 如何在静态 constexpr 类成员中使用 make_tuple() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45466327/