constexpr and virtual

constexpr and virtual

本文关键字:virtual and constexpr      更新时间:2023-10-16

我一直在想为什么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;
}

也就是说,我的问题是

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

由于constexpr是在C++11:中引入的,因此存在此限制

10.1.5constexpr说明符[dcl.constexpr]

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


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

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

事实上,目前的草案中已不存在这方面的措辞。

因为虚拟调用是通过运行时位于对象内存布局中的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)来解决多种情况,以解决编译时兼容的虚拟调用(例如,当所有内容都是constexpr时,它会记住你在指针/引用中放入了什么类型的实例),但这现在根本不是问题。

如果您想要一个运行时间接(virtual就是这样做的),那么也希望它在编译时执行是没有多大意义的。

第页。S: 很抱歉收到"编译时"answers"运行时"的垃圾邮件。

事实上,编译器有可能在编译时知道常量表达式的动态类型是什么。这是一种可能性,即优化器在编译时使用一些时间来破坏调用的机会。

但c++语言的发展也考虑到了在编译器中实现它的难度。如果不考虑这一点,那么c++标准将与c++编码的标准相距太远,因此它将是无用的。

也许,已经评估过,在常量表达式评估期间保持每个引用的静态类型的trac将过于昂贵,无法实现。这就是现实的伤害!