如何判断表达式是在编译时还是在运行时求值?

时间:2019-04-30 09:37:14

标签: c++ qt c++11

我有一个很大的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());
}

2 个答案:

答案 0 :(得分:6)

如果将结果分配给constexpr变量,用在static_assertnoexcept语句中或用作模板参数,则在编译时对表达式求值。这称为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构造函数(和默认构造函数)
  • 使用carrays和std::array
  • 使用static_asserts和其他东西
  • typedefusing声明

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

答案 1 :(得分:1)

  

还可以在编译时进行排序操作吗?

简短回答:否。

长答案。

否,因为std::sort()仅来自C ++ 20(您标记了C ++ 11),因为constexpr函数(void)不能为std::sort()在C ++ 11中为constexpr,因为QMapQList不是constexpr类(如果我没记错的话),因为您没有声明{{1 }}和其他涉及GMAP的对象,等等。

但是,假设有一个constexpr类定义了MyMap,一个constexpr类定义了MyList,一个constexpr函数定义了MySort(),您可以编写类似的内容(从C ++ 14开始,因为在C ++ 11中无法编写如此复杂的constexpr函数)

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

如果可能的话,这有必要强加(在C ++ 20之前)编译器初始化值编译时,或者在不可能的情况下给出编译错误。