我一直在想为什么constexr
和virtual
互相排斥,有人补充道:
... 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;
}
也就是说,我的问题是
答案 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
没有意义。因此,永远不会标记constexpr
和virtual
。
现在从技术上讲,根据代码复杂性,可以通过添加一个全新的系统(除了RTTI)来解析多个案例,以解决编译时兼容的虚拟调用(例如,当一切都是{时,某种形式的编译器元数据) {1}}会记住你在指针/引用中放入的实例类型,但现在根本就不是这样。
如果你想要一个运行时间接(这是constexpr
所做的那样),那么在编译时也不希望它被执行。
P.S:抱歉"编译时间"和"运行时"垃圾邮件。
答案 1 :(得分:3)
此限制自C ++ 11中引入constexpr
以来就存在:
10.1.5
constexpr
说明符[dcl.constexpr]
事实是,这可能只是一个疏忽。由于需要以常数表达式来知道对象的动态类型,因此此限制是不必要且人为的:这是Peter Dimov和Vassil Vassilev在P1064R0中断言的,他们建议将其删除。
实际上,current draft中不再存在该措词。
答案 2 :(得分:1)
实际上,编译器在编译时知道常量表达式的动态类型是可能。这是一种可能性,优化器在编译时使用一段时间来虚拟化调用。
但是c ++语言的演变也考虑到在编译器中实现它的难度。如果没有采取这样的考虑,那么c ++标准将远离c ++编码,因此它将是无用的。
也许,已经评估过,在常量表达式评估期间保持每个引用的静态类型的trac实现起来太昂贵了。这就是现实伤害的地方!