在编写自定义反射库时,我遇到了一个奇怪的编译器行为。然而,我能够用一个非常简单的代码来重现这个问题。以下是:
#include <iostream>
class OtherBase{};
class Base{};
/* Used only as a test class to verify if the reflection API works properly*/
class Derived : Base, OtherBase
{
public:
void Printer()
{
std::cout << "Derived::Printer() has been called" << std::endl;
}
};
/*Descriptor class that basically incapsulate the address of Derived::Printer method*/
struct ClassDescriptor
{
using type = Derived;
struct FuncDescriptor
{
static constexpr const auto member_address{ &type::Printer };
};
};
int main()
{
Derived derived;
auto address{ &Derived::Printer };
(derived.*address)(); // -> OK it compiles fine using the local variable address
(derived.*ClassDescriptor::FuncDescriptor::member_address)(); // -> BROKEN using the address from the descriptor class cause fatal error C1001 !
}在尝试调试此问题时,我注意到:
Derived具有多个继承时,才会发生这种情况。static constexpr const auto member_address{ &type::Printer }与inline static const auto member_address{ &type::Printer }交换,它就能工作。是编译错误,还是我做错了什么?我能在留住警员的同时解决这个问题吗?
请注意,我使用MSVC 2017与编译器版本19.16.27024.1所有编译器选项是默认的,除了/std:c++17启用。
我知道将编译器版本更新到最后一个版本可能会解决这个问题,但是现在我想更多地了解这个问题。
发布于 2020-07-27 02:45:20
此外,微软已经发布了解决此问题的解决方案。您可以安装最近发布。
const和constexprconst将对象声明为常量。这意味着,一旦初始化,该对象的值就不会改变,编译器可以利用这一事实进行优化。它还有助于防止程序员编写修改初始化后不打算修改的对象的代码。
constexpr将一个对象声明为适合于标准称为常量表达式的对象。但是请注意,constexpr并不是唯一的方法。
当应用于功能时,基本区别是:
const只能用于非静态成员函数,而不能用于一般函数.它保证成员函数不会修改任何非静态数据成员。
constexpr既可用于成员函数,也可用于非成员函数以及构造函数.它声明函数适合在常量表达式中使用。只有当函数满足某些标准(7.1.5/3,4)时,编译器才会接受它,最重要的是:
函数体必须是非虚拟的,并且非常简单:除了类型防御和静态断言之外,只允许一个return语句。对于构造函数,只允许初始化列表、类型防御和静态断言。(不过,= default和= delete也是允许的。)对于C++14,规则更加宽松,从那时起在constexpr函数中允许什么:asm声明、goto语句、带有case和default以外标签的语句、try-块、非文字类型变量的定义、静态或线程存储持续时间变量的定义、不对其执行初始化的变量的定义。参数和返回类型必须是文字类型(一般来说,非常简单的类型,通常是标量或聚合)。
我什么时候可以/应该同时使用const和constexpr?
A.在目标声明中。当两个关键字都引用要声明的同一个对象时,这是不必要的。constexpr暗示着康斯特。
constexpr const int N = 5;
is the same as
constexpr int N = 5;但是,请注意,在某些情况下,每个关键字都引用声明的不同部分:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
}在这里,NP被声明为一个地址常量表达式,即一个指针本身就是一个常量表达式.(当通过将地址运算符应用于静态/全局常量表达式生成地址时,这是可能的。)在这里,constexpr和const都是必需的:constexpr总是引用被声明的表达式(在这里是NP),而const是指int (它声明了一个指向const的指针)。删除const将使表达式成为非法(因为(a)指向非const对象的指针不能是常量表达式,(b) &N实际上是指向常量的指针)。
B.成员职能声明。在C++11中,constexpr意味着const,而在C++14和C++17中,情况并非如此。在C++11下声明为
constexpr void f();
needs to be declared as
constexpr void f() const;在C++14下,以便仍然可以用作const函数。
有关更多细节,您可以参考此链接。
https://stackoverflow.com/questions/63076635
复制相似问题