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