首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用指针到方法的MSVC编译器致命错误C1001

使用指针到方法的MSVC编译器致命错误C1001
EN

Stack Overflow用户
提问于 2020-07-24 15:24:05
回答 1查看 170关注 0票数 1

在编写自定义反射库时,我遇到了一个奇怪的编译器行为。然而,我能够用一个非常简单的代码来重现这个问题。以下是:

代码语言:javascript
复制
#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 !
}

在尝试调试此问题时,我注意到:

  1. 只有当Derived具有多个继承时,才会发生这种情况。
  2. 如果我将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启用。

我知道将编译器版本更新到最后一个版本可能会解决这个问题,但是现在我想更多地了解这个问题。

EN

回答 1

Stack Overflow用户

发布于 2020-07-27 02:45:20

  1. 关于C1001,建议您删除代码中的一些优化:致命错误C1001。一旦确定了是哪种优化导致了问题,就可以在该领域使用#实用化来禁用该优化: //禁用优化#务实优化( "",off ). //重新启用以前的任何优化#务实优化( "",on )

此外,微软已经发布了解决此问题的解决方案。您可以安装最近发布

  1. constconstexpr

const将对象声明为常量。这意味着,一旦初始化,该对象的值就不会改变,编译器可以利用这一事实进行优化。它还有助于防止程序员编写修改初始化后不打算修改的对象的代码。

constexpr将一个对象声明为适合于标准称为常量表达式的对象。但是请注意,constexpr并不是唯一的方法。

当应用于功能时,基本区别是:

const只能用于非静态成员函数,而不能用于一般函数.它保证成员函数不会修改任何非静态数据成员。

constexpr既可用于成员函数,也可用于非成员函数以及构造函数.它声明函数适合在常量表达式中使用。只有当函数满足某些标准(7.1.5/3,4)时,编译器才会接受它,最重要的是:

函数体必须是非虚拟的,并且非常简单:除了类型防御和静态断言之外,只允许一个return语句。对于构造函数,只允许初始化列表、类型防御和静态断言。(不过,= default= delete也是允许的。)对于C++14,规则更加宽松,从那时起在constexpr函数中允许什么:asm声明、goto语句、带有casedefault以外标签的语句、try-块、非文字类型变量的定义、静态或线程存储持续时间变量的定义、不对其执行初始化的变量的定义。参数和返回类型必须是文字类型(一般来说,非常简单的类型,通常是标量或聚合)。

我什么时候可以/应该同时使用constconstexpr

A.在目标声明中。当两个关键字都引用要声明的同一个对象时,这是不必要的。constexpr暗示着康斯特。

代码语言:javascript
复制
constexpr const int N = 5;
is the same as

constexpr int N = 5;

但是,请注意,在某些情况下,每个关键字都引用声明的不同部分:

代码语言:javascript
复制
static constexpr int N = 3;

int main()
{
  constexpr const int *NP = &N;
}

在这里,NP被声明为一个地址常量表达式,即一个指针本身就是一个常量表达式.(当通过将地址运算符应用于静态/全局常量表达式生成地址时,这是可能的。)在这里,constexprconst都是必需的:constexpr总是引用被声明的表达式(在这里是NP),而const是指int (它声明了一个指向const的指针)。删除const将使表达式成为非法(因为(a)指向非const对象的指针不能是常量表达式,(b) &N实际上是指向常量的指针)。

B.成员职能声明。在C++11中,constexpr意味着const,而在C++14和C++17中,情况并非如此。在C++11下声明为

代码语言:javascript
复制
constexpr void f();
needs to be declared as

constexpr void f() const;

在C++14下,以便仍然可以用作const函数。

有关更多细节,您可以参考此链接

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63076635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档