C ++ - 我可以创建编译时变量对象吗?

时间:2018-01-06 18:39:13

标签: c++ variables constexpr compile-time

我最近使用的是constexpr,但我刚才意识到我错了。我很好奇是否可以创建编译时变量(或变量对象) 来自cppreference.com的constexpr定义告诉我们:

  

constexpr说明符声明可以在编译时评估函数或变量的值。

那么为什么以下代码不正确?

#include <iostream>

int main()
{
    constexpr int x = 30;
    x += 10;
    std::cout << x;
}

可以在编译时完美地评估此整数。我知道编译器可以在没有constexpr修饰符的情况下优化这样的变量,但是如果我想要一个编译时对象呢?

#include <iostream>

class ctFoo {
public:
    ctFoo()
        : value{ 0 }
    {
    }
    int accumulate(int value_) {
        return (value += value_), value;
    }
    int value;
};

int main()
{
    ctFoo foo;
    std::cout << foo.accumulate(100);
}

我有什么确定性,这段代码将在编译时进行评估? 我问这个,因为我正在编写一些Vector2和Vector3数学,我想创建这样的实现,它将能够处理编译时和运行时计算。甚至可能吗?
感谢。

修改

正如max66所指出的,constexpr意味着const,但我在问:为什么会这样?现代编译器应该能够在编译时推断出它的价值。 另外,我知道我可以简单地创建另一个constexpr常量(广告顶级代码示例),但我的问题是指更复杂的代码。

2 个答案:

答案 0 :(得分:3)

  

那么为什么以下代码不正确?

#include <iostream>

int main()
{
    constexpr int x = 30;
    x += 10;
    std::cout << x;
}

constexpr暗示const。您需要将此约束为constexpr上下文:

constexpr int foo() {
    int x = 30;
    x += 10;
    return x;
}
  

但是如果我想要一个编译时对象呢?

#include <iostream>

class ctFoo {
public:
    ctFoo()
        : value{ 0 }
    {
    }
    int accumulate(int value_) {
        return (value += value_), value;
    }
    int value;
};

给予constexpr支持:

constexpr ctFoo() : value{ 0 }

constexpr int accumulate(int value_) {
    value += value_;
    return value;
}

您现在的保证是,如果您的ctFoo对象是常量表达式并且您在accumulate上下文中调用constexpr,例如foo函数示例,那么您可以在编译时使用结果。例如:

constexpr int foo() {
    ctFoo f;
    f.accumulate(10);
    return f.value;
}

static_assert(foo() == 10);

或者:

constexpr void accumulate(ctFoo& f) {
    f.accumulate(10);
}

constexpr int foo() {
    ctFoo f;
    accumulate(f);
    return f.value;
}

static_assert(foo() == 10);

这里要记住的关键是运行时评估也是一种选择。如果我将一些ctFoo的{​​{1}}设置为运行时值(例如,用户输入),则在编译时无法进行value调用。但这没关系 - 相同的代码在两种情况下都有效。

答案 1 :(得分:1)

您需要继续阅读:

  

对象声明中使用的constexpr说明符隐含const

你无法改变constexpr,这就是你能够在常量表达式中使用它的全部意义。

接下来要考虑的是你似乎在混合两种不同的语境。我毫不怀疑编译器能够完全优化你的最后一个例子,但这是constexpr所做的其他事情。关键字表示在编译时可以可以表示它的含义,但不一定要这样。因此,您可以编写一个constexpr函数,其中的所有内容都可能在编译时进行评估,并且仍然可以在运行时运行。

唯一可以真正拥有可以在编译时评估的对象(因此没有优化器)并且可以修改的时间是在编译时上下文中。您处于这样的环境中,例如在constexpr函数中:

constexpr int foo() {
    int a = 10;
    ++a; // I can modify a.
    return a;
    // even if I did this: int Array[foo()];
}

但是你在正常的功能中没有这种能力,语言就是不允许它。

所以,回答你的问题:

  

我有什么确定性,这段代码将在编译时进行评估?

您没有,因为您没有使用constexpr。即便如此,如果你在不需要编译时评估的某个地方调用constexpr函数,那么该函数可能会在运行时被调用,

  

甚至可能吗?

当然,如上所述,您创建了一个constexpr函数,如果需要,将在编译时对其进行评估。