c++ - 通过使返回的 obj 常量,强制在编译时编译 constexpr 函数,即使内部计算包含非常量数组?

标签 c++ compilation constexpr compile-time-constant

我阅读了有关 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

所以你必须constexprArray 的构造函数上在任何情况下,如果您的程序应该是格式良好的。

在常量表达式内部创建的变量(例如 calculations )是否为 const一点都不重要。

关于c++ - 通过使返回的 obj 常量,强制在编译时编译 constexpr 函数,即使内部计算包含非常量数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58780650/

相关文章:

c++ - 错误 : ‘memset’ was not declared in this scope

c++ - 从 Qt 中的 Web 服务解析未命名的 JSON 数组

C++ 完美数。需要一些帮助修改

c++ - 在cpp中运行一个计时器,与正在执行的程序并行

compilation - 自定义控制流编译词示例

plugins - Gradle 编译依赖项未包含在 Jar 中

c++ - 如何测试 constexpr 是否被正确评估

c++ - constexpr 数组未定义

c++ - 复制 C 风格的数组和结构

c++ - Constexpr 可构造函数对象