将 static constexpr class 成员分配给运行时变量
Assign static constexpr class member to runtime variable
我知道有很多类似的问题,但不知何故不同的问题。关于以下情况:
#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
变量的中间步骤来完成。
所以我的问题是:为什么不能将 class 的静态 constexpr 成员分配给运行时变量?
注意:在我的 MWE 中,class 是一个模板 class,它不会影响错误。但是,我最初对这种特殊情况感兴趣,我希望它对于非模板更通用 class.
(编译器是 clang++
或 g++
与 -std=c++11
- 他们给出相同的错误)
编辑:@Bryan Chen:忘记了输出行。现已添加。
出于这个原因,我总是 return 来自 constexpr 函数的 constexpr 对象。
修改以下代码。请注意,由于 std::array<>
中的 c++14 缺陷,您必须 return 一个 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
undefined reference
是链接器错误。规则是如果一个变量是 odr-used 那么它必须有一个定义。这甚至适用于 constexpr
个变量。
与大多数 ODR 规则一样,违反它是未定义的行为,不需要诊断(这可以解释为什么您没有看到对值的某些使用的诊断)。
要修复错误,请在 class:
之外添加一个定义
template<typename T> constexpr std::array<T,4> MyClass<T>::ARRAY;
因为它是一个模板,您实际上可以将它放在 header 中,而不是通常情况下定义只放在一个 .cpp
文件中。
这里的主要问题是ARRAY[0]
是否算作odr-use。根据 this detailed post, in C++11 and C++14, indexing an array does count as odr-use , but this was changed by DR 1926 对 C++14 提出的要求不是 odr-use.
但是,这是在谈论内置数组。 IDK是否同样的理由适用于std::array
,我发现[basic.def.odr]/3的文字很难理解。根据 informal definition on cppreference,std::array::operator[]
会导致数组的 odr-use,因为它的 return 值绑定了对数组的引用。
我知道有很多类似的问题,但不知何故不同的问题。关于以下情况:
#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
变量的中间步骤来完成。
所以我的问题是:为什么不能将 class 的静态 constexpr 成员分配给运行时变量?
注意:在我的 MWE 中,class 是一个模板 class,它不会影响错误。但是,我最初对这种特殊情况感兴趣,我希望它对于非模板更通用 class.
(编译器是 clang++
或 g++
与 -std=c++11
- 他们给出相同的错误)
编辑:@Bryan Chen:忘记了输出行。现已添加。
出于这个原因,我总是 return 来自 constexpr 函数的 constexpr 对象。
修改以下代码。请注意,由于 std::array<>
中的 c++14 缺陷,您必须 return 一个 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
undefined reference
是链接器错误。规则是如果一个变量是 odr-used 那么它必须有一个定义。这甚至适用于 constexpr
个变量。
与大多数 ODR 规则一样,违反它是未定义的行为,不需要诊断(这可以解释为什么您没有看到对值的某些使用的诊断)。
要修复错误,请在 class:
之外添加一个定义template<typename T> constexpr std::array<T,4> MyClass<T>::ARRAY;
因为它是一个模板,您实际上可以将它放在 header 中,而不是通常情况下定义只放在一个 .cpp
文件中。
这里的主要问题是ARRAY[0]
是否算作odr-use。根据 this detailed post, in C++11 and C++14, indexing an array does count as odr-use , but this was changed by DR 1926 对 C++14 提出的要求不是 odr-use.
但是,这是在谈论内置数组。 IDK是否同样的理由适用于std::array
,我发现[basic.def.odr]/3的文字很难理解。根据 informal definition on cppreference,std::array::operator[]
会导致数组的 odr-use,因为它的 return 值绑定了对数组的引用。