c++ - 如何在静态 constexpr 类成员中使用 make_tuple() ?

标签 c++ c++11 constexpr

我正在尝试在 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.4clang 3.4 以及 -std=c++11

最佳答案

在 C++11/14 中,如果使用 ODR,static constexpr 变量必须在某处定义(ODR 使用的意思是“以需要它具有的方式使用”一个身份”。举个例子,取一个真正的引用或指向它们的指针。这里的 ODR 意思是“一个定义规则”,ODR-used 意思是“在要求它有一个定义的意义上使用”,我将其缩写为“有一个身份”)。

Simply add:

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/

相关文章:

c++ - QList 默认参数错误消息(QList<QVariant> 的默认参数类型为 int)

c# - C#中的CRC16计算?

c++ - 有没有办法使 unique_ptr 的实例化不那么冗长?

c++ - 如何包装 "expanded variadic template parameters"?

c++ - 静态类成员的初始化。为什么要构造函数?

c++ - 在编译时通过 constexpr 或模板函数获取多维 std::array 的大小

c++ - 使用 C++ 编写带有字节顺序标记 (BOM) 的 csv 文件?

C++ 完美函数转发

c++ - 通过引用调用 constexpr 方法 - 结果是常量表达式吗?

c++ void 只有参数类型