如何判断表达式是在编译时还是运行时评估的?
Posted
技术标签:
【中文标题】如何判断表达式是在编译时还是运行时评估的?【英文标题】:How to tell if expression is evaluated at compile time or runtime? 【发布时间】:2019-04-30 09:37:13 【问题描述】:我有一个相当大的 Map 对象,我想要一个单独的列表,其中的键已排序。这将在我项目的许多其他源文件中使用。
问题是我如何知道声明/定义何时是编译时作业。如果是这种情况,我应该在哪里寻找?我的意思是如何分辨?
在以下示例中,源文件中的列表是编译时作业还是发生在运行时?
另外,有没有办法在编译时进行排序操作?
// global.h
extern QMap<int, QString> G_MAP;
extern QList<int> G_MAP_SKEYS_SORTED;
// global.cpp
QMap<int, QString> G_MAP = /* some hand filled (static) data */ ;
QList<int> G_MAP_SKEYS_SORTED = G_MAP.keys();
// main.cpp
int mian()
// Somewhere I do the sort
std::sort(G_ListRegistersSorted.begin(), G_ListRegistersSorted.end());
【问题讨论】:
只是一个想法:你可以static_assert
它的大小并让编译器解释。
如果从some data
构造的QMap
(或QList
)包含动态内存分配,根据定义,它不能在编译期间完成。
@AlgirdasPreidžius 初始化列表是手动填充的,所以它不是动态的
std::sort()
是 constexpr
仅从 C++20 开始;所以之前(你标记了 C++11)肯定不是。
本例中唯一在编译时评估的是初始化列表: /* some hand filled (static) data */ ;
。
【参考方案1】:
如果将结果分配给constexpr
变量、在static_assert
或noexcept
语句中使用或用作模板参数,则在编译时计算表达式。这称为 constexpr 上下文。
例如:
// Function which can calculate the fibbonacci sequence at compiletime
constexpr int fib(int n)
if(n == 0 || n == 1) return n;
return fib(n - 1) + fib(n - 2);
int main()
// This one is calculated at compiletime
constexpr int fib10_at_compiletime = fib(10);
// This one is calculated at runtime
// (unless the compiler was really aggressive when doing optimizations)
int fib10_at_runtime = fib(10);
为了在编译时调用函数或其他东西,需要将其标记为constexpr
。
编译时可以做什么?
C++11:
声明变量(但不要修改它们) 调用其他 constexpr 函数 调用 constexpr 构造函数(和默认构造函数) 使用数组和std::array
使用 static_asserts 之类的东西
typedef
和 using
声明
C++14 补充:
您现在也可以使用 lambdas 您可以在 constexpr 函数中修改变量 你可以拥有改变成员变量的 constexpr 成员函数 您可以将引用(非 const 类型)传递给 constexpr 函数C++20 新增功能:(C++20 将于 2020 年推出)
您现在可以分配内存 现在可以调用虚函数了 您可以拥有try-catch
块
是std::sort
constexpr 吗?
为了在 constexpr 上下文中使用函数,必须将其标记为 constexpr(这对您可以在函数中执行的操作有一组限制;这些将在下面讨论)。在 C++11 中,std::sort
不是 constexpr,因为它打破了这些限制(在 C++20 之前它不会是 constexpr)。
但是,如果您被允许使用 C++14,您可以编写自己的排序函数,在编译时工作。
完整概述: https://en.cppreference.com/w/cpp/language/constexpr
【讨论】:
谢谢!希望对您有所帮助!【参考方案2】:另外,有没有办法在编译时进行排序操作?
简短回答:不。
长答案。
不,因为 std::sort()
是 constexpr
仅来自 C++20(您标记了 C++11),因为 void
函数 (std::sort()
) 在 C++11 中不能是 constexpr
,因为QMap
和QList
不是constexpr
类(如果我没记错的话),因为您还没有将GMAP
和其他涉及的对象声明为constexpr
等。
但是,假设有一个MyMap
类定义constexpr
,一个MyList
类声明constexpr
,一个MySort()
函数定义constexpr
,你可以写类似的东西(从C++14 开始因为在 C++11 中你无法编写如此复杂的constexpr
函数)
constexpr MyList foo ()
MyMap mm /* some values */ ;
MyList ml ml.keys() ;
MySort(ml.begin(), ml.end());
return ml;
// ...
constexpr auto ml_final foo() ;
注意ml_final
被声明为constexpr
。
这对于强制(C++20 之前)编译器在可能的情况下在编译时初始化值是必要的,或者在不可能的情况下给出编译错误。
【讨论】:
以上是关于如何判断表达式是在编译时还是运行时评估的?的主要内容,如果未能解决你的问题,请参考以下文章
在引用 POM 而不是定义 POM 时评估的嵌套 Maven 属性