我了解了constexpr
函数以及它们何时进行编译时计算。现在,我必须要用新值填充数组,因此数组不能为const
。
据我所知,当函数中的每个值都是constexpr
且使用的函数是const
(也仅使用constexpr
值)时,肯定会在编译时评估const
函数。此外,另一篇文章指出,可以通过使返回的obj const
强制进行编译时编译。
可以说,我的函数是一个constexpr
,但是里面有一个non-const
数组,但是返回的对象将是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);
}
最佳答案
据我所知,当函数内部的每个值都是const并且使用的函数是constexpr(也只使用const值)时,肯定会在编译时评估constexpr函数。此外,另一篇文章指出,可以通过使返回的obj常量来强制进行编译时编译。
所有这些陈述都是错误的。见下文。
不可以,如果在需要(编译时)常量表达式的上下文中调用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
来强制其始终在编译时求值。目前,如果不进行例如返回值的目的地是constexpr
变量。实际上,您的原始代码具有未定义的行为。因为
Array
没有constexpr
构造函数,所以永远不能在常量表达式中构造该类型的对象。并且由于Example
使用该类型,因此它也不能在常量表达式中使用。这使将constexpr
放在其构造函数上是非法的,因为如果没有至少一组有效的模板参数和函数参数会产生常量表达式,则声明为constexpr
的函数会导致未定义的行为。 (这同样适用于calculations
,因为它使用Example
。因此,如果程序的格式正确,则无论如何都必须将
constexpr
放在Array
的构造函数中。在常量表达式内部创建的变量(例如在
calculations
内部)是否为const
根本不重要。