我有这样的代码
const int Value = 123 * 2 + GetOffset();
GetOffset
是一个返回int
的constexpr
函数。
如何确保在编译时确实计算了此表达式?
你为什么不把constexpr
也用于价值?我认为它会要求编译器对其进行评估,
constexpr int Value = 123 * 2 + GetOffset();
如果函数 GetOffset(( 很简单并且满足 constexpr
的要求。
要求是
该函数必须具有非 void 返回类型。
函数体不能声明变量或定义新类型。
正文只能包含声明、NULL 语句和单个返回陈述。
由于Getoffset()
返回int
,它满足了第一个。
您无法确保编译器执行此操作。通常需要启用优化,包括某种级别的函数内联。这些选项是什么取决于您的编译器及其版本。
可以检查生成的程序集,以查看它是否包含对GetOffset
的调用或仅使用编译器确定的常量。
如果你也声明"Value"为constexpr怎么办?实际上,您永远无法确定是否在编译时评估了某些内容,但是在这种情况下,没有理由无法对其进行评估。
一种可能性是使用 std::ratio
。 从 C++11 标准的第 20.10.1 节:
此子子句描述比率库。它提供了一个类模板比率,该比率精确地表示任何有限有理数,分子和分母可由 intmax_t 类型的编译时常量表示。
因此,根据标准,这仅对编译时常量有效:
const int value = std::ratio<123 * 2 + GetOffset()>::num;
因此,这将保证在编译时计算表达式。 但是,它也不能保证在运行时不计算表达式。
你不能绝对确定;编译器只需要生成具有指定行为的代码,在编译或运行时计算它不会改变行为。
但是,编译器需要能够在编译时对此进行评估,因为它可以在只允许编译时常量(如数组大小和模板参数(的情况下使用;因此,理智的编译器没有理由不执行明显的优化。如果编译器没有(至少在启用优化的情况下(,请将其丢弃并找到更好的编译器。
您可以检查编译器生成的程序集,以查看它是否计算值;但这本身并不能保证将来的构建也会这样做。
考虑到我已经五年多没有使用C++了,建议成为标记方式的可能性很高,但是使用内联函数呢?
如果函数返回在编译时可用的某个预定义值,则编译器应该能够使用该值。
使用表达式创建单独的源文件。评估printf("#define MyExpression %d.n", expression);
。生成项目时,请为本机系统编译此源文件并执行它。将生成的输出作为标头包含在常规源中。
如果要确认初始值设定项是常量表达式,则可以使用constexpr
说明符:
constexpr int Value = 123 * 2 + GetOffset();
如果它不是常量表达式,则编译失败。
理论上没有指定 constexpr 变量Value
是否在翻译过程中实际计算 - 但在实践中您可以确定它是。
只是断言它:static_assert(Value == 123 * 2 + GetOffset(), "constexpr");
没有比这更简单