2017-08-02 40 views
1

我正在尝试在constexpr中使用make_tuple()。它在全球范围内运作。但它会为static constexpr类成员生成链接错误。如何在静态constexpr类成员中使用make_tuple()?

#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' 

} 

我已经检查heremake_tuple它本身也不是一个c++11constexpr。我猜这在这种情况下不是问题。如果是的话,它会产生一个编译错误,而不是链接错误。

我试图定义constexpr类的外部波纹一样通过this answer

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

static constexpr类成员中使用make_tuple的正确方法是什么?

编译器: g++ 4.8.4clang 3.4-std=c++11

+0

[很适合我](http://coliru.stacked-crooked.com/a/bc0d0fef61b17c97)。 – user0042

+0

悲伤地不与非内在的对象。使用静态constexpr函数来传递对象。 –

+0

这个编译器的g ++版本是什么? – army007

回答

4

在C++ 11/14,static constexpr变量必须定义在需要它有一个的方式使用某处如果使用的ODR(使用的ODR手段”一个身份“,例如,给他们一个真正的参考或指针,ODR在这里意味着”一个定义规则“,而ODR使用的意思是”在某种意义上使用,它要求它只有一个定义“,我缩短为“有一个身份”)。

Simply add:

constexpr tuple<int, double> A::z; 

和我们定义它的存在。这需要恰好在一个编译单元中。

在C++ 17中,添加了inline变量,我相信constexpr变量是隐式地内联的。我不是C++ 17专家,但是没有定义的it compiles and runs in C++1z mode,所以我的解释似乎至少有一半是正确的。

inline变量,如inline功能,在结束了该定义创建的任何地方编译就是了。inline功能通常由具有与特殊说明的每个目标文件的定义,当有人需要它的一个地址,则实施重复在链接时被丢弃,每个人都指最后一个站点。我不知道inline变量倾向于以相同的方式实现)

如果你想在C++ 11中解决这个问题而无需在硬编码模板参数.cpp文件change z to a constexpr function中添加内容,并在需要时使用它。


正如SergyA提到,ODR这里触发,因为get返回参考一个字段中的元组,并参考暗示的身份必须存在的领域,因此整个数组。

从理论上讲,按价值返回的精心制作的value_get可以避免此ODR的使用,但它取决于tuple的实现,因为它反过来不能调用get

+2

我只是补充说,这里的ODR使用情况是由于get <>返回一个引用的事实。我想,应该可以做my_get <>返回值,这不会触发问题。 – SergeyA

+0

*定义*,未声明。隐式内联仅适用于静态数据成员。 –

+0

@ yakk感谢您解释它是如何违反ODR和建议使其具有“constexpr”功能。 – army007