我知道有很多类似的问题,但不知怎的问题。这是关于以下情况:
#include <iostream>
#include <array>
template<typename T> class MyClass
{
public:
static constexpr std::array<T,4> ARRAY {{4, 3, 1, 5}};
};
int main()
{
constexpr std::array<int, 4> my_array(MyClass<int>::ARRAY); // works fine -> can use the ARRAY to initialize constexpr std::array
constexpr int VALUE = 5*MyClass<int>::ARRAY[0]; // works also fine
int value;
value = my_array[0]; // can assign from constexpr
value = MyClass<int>::ARRAY[0]; // undefined reference to `MyClass<int>::ARRAY
std::cout << VALUE << std::endl;
std::cout << value << std::endl;
return 0;
}
据我所知constexpr
是编译时常量。因此编译器可以进行一些计算,例如计算VALUE
。此外,我可以明确地定义constexpr std::array<,>
,我可以从中将值分配给运行时变量。我希望编译器已经将value = 4
设置为可执行程序,以避免加载操作。但是,我不能直接从静态成员分配,得到错误
undefined reference to `MyClass<int>::ARRAY'
clang-3.7: error: linker command failed with exit code 1
这对我没有意义,因为它可以通过另一个constexpr
变量的中间步骤来完成。
所以我的问题是:为什么不能将类的静态constexpr成员分配给运行时变量?
注意:在我的MWE中,类是模板类,不会影响错误。但是,我最初对这个特殊情况很感兴趣,对于非模板类,我希望它更为通用。
(编译器为clang++
或g++
,-std=c++11
- 他们会出现同样的错误)
编辑:@Bryan Chen:忘记输出线。现在加入。
答案 0 :(得分:7)
undefined reference
是链接器错误。规则是,如果变量是 odr-used ,那么它必须有一个定义。这甚至适用于constexpr
变量。
与大多数ODR规则一样,违反它是未定义的行为,不需要诊断(这可以解释为什么您没有看到对该值的某些使用的诊断)。
要修复错误,请在类外添加定义:
template<typename T> constexpr std::array<T,4> MyClass<T>::ARRAY;
由于它是一个模板,你实际上可以将它放在标题中,而不是通常只有一个.cpp
文件中的定义。
这里的主要问题是ARRAY[0]
是否算作 odr-use 。根据{{3}},在C ++ 11和C ++ 14中,对数组建立索引的确计为 odr-use ,但这是由针对C +提交的this detailed post更改的+14不是 odr-use 。
然而,这是在讨论内置数组。 IDK是否同样的理由适用于std::array
,我发现[basic.def.odr] / 3的文本难以理解。根据{{3}},std::array::operator[]
会导致数组的 odr-use ,因为它的返回值会绑定对数组的引用。
答案 1 :(得分:4)
因此我总是从constexpr函数返回constexpr对象。
下面的修改代码。请注意,由于std::array<>
中的c ++ 14不足,您必须返回const std::array
才能允许operator[]
生效。
#include <iostream>
#include <iostream>
#include <array>
template<typename T> class MyClass
{
public:
static constexpr const std::array<T,4> ARRAY() { return {4, 3, 1, 5}; };
};
int main()
{
constexpr std::array<int, 4> my_array(MyClass<int>::ARRAY()); // works fine -> can use the ARRAY to initialize constexpr std::array
constexpr int VALUE = 5 * MyClass<int>::ARRAY()[0]; // works also fine
int value;
value = my_array[0]; // can assign from constexpr
value = MyClass<int>::ARRAY()[0]; // undefined reference to `MyClass<int>::ARRAY
std::cout << VALUE << std::endl;
std::cout << value << std::endl;
return 0;
}
预期结果:
20
4