我阅读了有关 constexpr
函数的内容以及它们何时进行编译时计算。现在我必须用新值填充一个数组,因此该数组不能是 const
。
据我所知,constexpr
函数肯定在编译时求值,函数中的每个值都是 const
并且使用的函数是 constexpr
也只使用 const
值。此外,另一篇文章指出,可以通过使返回的 obj const
强制编译时编译。
比方说,我的函数是一个constexpr
,但内部有一个非常量
数组,但返回的对象将是const
。我的函数 calculation
会在编译时被评估吗(强制?)。
template<int Size, typename T>
struct Array{
T array[Size];
Array(const T * a){
for(int i = 0; i < Size; i++){
array[i] = a[i];
}
}
};
template<typename T, int size>
class Example{
private:
Array<size, T> _array;
public:
constexpr explicit Example(T * arr):_array(arr){};
constexpr explicit Example(const T * arr):_array(arr){};
};
template<typename D, int size, typename ...buf, typename T>
constexpr auto calculations(const T & myObj){
D test1[2];
// calculation fills arr
return Example<D, size>(test1);
}
int main(){
const int size = 2;
const double test1[size] = {1,2};
const auto obj1 = Example<double, size>(test1); //compile time
//obj2 calculations during compile time or run-time?
const auto obj2 = calculations<double, size>(obj1);
}
最佳答案
From what i know, a constexpr function is definitely evaluated at compile time, when every value inside the function is const and used functions are constexpr which also only use const values. Furthermore, an other post stated, that it's possible to force a compile time compilation by making the returned obj const.
所有这些说法都是错误的。见下文。
不,调用 constexpr
只有在需要(编译时)常量表达式的上下文中调用函数时,才能保证在编译时对其求值。 obj2
的初始化程序不是这样的上下文,即使它是 const
.
您可以通过声明 obj2
来强制对初始化器进行编译时求值。作为constexpr
. (然而,这与 const
的含义截然不同!)
即使那样它也不会起作用,因为calculations<double, size>(obj1)
实际上不是常量表达式。 obj1
在未声明的情况下不是编译时常量 constexpr
以及。同样,这也行不通,因为 test1
不声明就不是常量表达式constexpr
然后你还需要构造Array
的构造函数constexpr
你需要实际填写 test1
的值里面calculations
,因为访问未初始化的值会导致未定义的行为,而未定义的行为会使表达式不是常量表达式。
总而言之:
template<int Size, typename T>
struct Array{
T array[Size];
constexpr Array(const T * a) {
for(int i = 0; i < Size; i++){
array[i] = a[i];
}
}
};
template<typename T, int size>
class Example{
private:
Array<size, T> _array;
public:
constexpr explicit Example(T * arr):_array(arr){};
constexpr explicit Example(const T * arr):_array(arr){};
};
template<typename D, int size, typename ...buf, typename T>
constexpr auto calculations(const T & myObj){
D test1[2];
test1[0] = 0;
test1[1] = 1;
// calculation fills arr
return Example<D, size>(test1);
}
int main(){
const int size = 2;
constexpr double test1[size] = {1,2};
constexpr auto obj1 = Example<double, size>(test1); //compile time
//obj2 calculations during compile time or run-time?
constexpr auto obj2 = calculations<double, size>(obj1);
}
在 C++20 中会有一个替代关键字 consteval
哪个可以用来代替 constexpr
在一个函数上强制它总是在编译时被评估。目前没有办法做到这一点,例如返回值的目的地 a constexpr
变量。
事实上,您的原始代码具有未定义的行为。因为Array
没有 constexpr
构造函数,该类型的对象永远不能在常量表达式中构造。因为Example
使用该类型,它也不能用于常量表达式。这使得放置 constexpr
是非法的在其构造函数上,因为函数声明为 constexpr
如果没有至少一组有效的模板参数和函数参数可以生成常量表达式,则会导致未定义的行为。 (同样适用于 calculations
,因为它使用 Example
。
所以你必须把constexpr
在 Array
的构造函数上在任何情况下,如果您的程序应该是格式良好的。
在常量表达式内部创建的变量(例如 calculations
)是否为 const
一点都不重要。
关于c++ - 通过使返回的 obj 常量,强制在编译时编译 constexpr 函数,即使内部计算包含非常量数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58780650/