constexpr和虚拟

时间:2017-11-14 05:46:39

标签: c++ c++11

我一直在想为什么constexrvirtual互相排斥,有人补充道:

  

... constexpr是关于编译时的执行;如果我们在编译时执行该函数,我们显然知道它在编译时所处理的数据的类型,这么晚的绑定显然不是相关的。

但是,即使在编译时,动态类型也可能与静态类型不同,并且可能存在需要动态类型的情况:

class A {
public:
    /* virtual */ constexpr int foo() {
        return 1;
    }
};

class B : public A {
public:
    constexpr int foo() {
        return 2;
    }
};

constexpr int foo(A &a) {
    // The static type is fixed here.
    // What if we want to call B::foo() ?
    return a.foo();
}

int main() {
    B b;
    constexpr int c = foo(b);
    return 0;
}

也就是说,我的问题是

  • 该标准背后的(可能的)理由是什么,禁止两者结合?

3 个答案:

答案 0 :(得分:3)

因为虚拟调用是在运行时通过位于对象内存布局中的vtables / RTTI(运行时类型信息)解析的,所以" true类型" "后面使用的对象句柄"在编译时不知道。

在你的例子中:

constexpr int foo(A &a) {
    // The static type is fixed here.
    // What if we want to call B::foo() ?
    return a.foo();
}

如果foo成员函数是虚拟的,则无法在编译时执行该foo函数。如果函数永远不能在编译时执行,则将函数标记为constexpr没有意义。因此,永远不会标记constexprvirtual

现在从技术上讲,根据代码复杂性,可以通过添加一个全新的系统(除了RTTI)来解析多个案例,以解决编译时兼容的虚拟调用(例如,当一切都是{时,某种形式的编译器元数据) {1}}会记住你在指针/引用中放入的实例类型,但现在根本就不是这样。

如果你想要一个运行时间接(这是constexpr所做的那样),那么在编译时也不希望它被执行。

P.S:抱歉"编译时间"和"运行时"垃圾邮件。

答案 1 :(得分:3)

此限制自C ++ 11中引入constexpr以来就存在:

  

10.1.5 constexpr说明符[dcl.constexpr]

     

3 constexpr函数的定义应满足以下要求:
  (3.1) -它不能是虚拟的;


但是您在问的是此限制的原理,而不是该限制本身。

事实是,这可能只是一个疏忽。由于需要以常数表达式来知道对象的动态类型,因此此限制是不必要且人为的:这是Peter Dimov和Vassil Vassilev在P1064R0中断言的,他们建议将其删除。

实际上,current draft中不再存在该措词。

答案 2 :(得分:1)

实际上,编译器在编译时知道常量表达式的动态类型可能。这是一种可能性,优化器在编译时使用一段时间来虚拟化调用。

但是c ++语言的演变也考虑到在编译器中实现它的难度。如果没有采取这样的考虑,那么c ++标准将远离c ++编码,因此它将是无用的。

也许,已经评估过,在常量表达式评估期间保持每个引用的静态类型的trac实现起来太昂贵了。这就是现实伤害的地方!