返回前向声明的枚举类是否有效?(Visual Studio 2015 链接器错误)
Is It Valid To Return Forward Declared Enum Class? (Visual Studio 2015 Linker Error)
我有一个问题,以下代码在GCC(4.8+测试)和Clang(3.4+测试)上编译,但不能在Visual Studio 2015(VC++ 14.0)上编译。
噗
:#include <functional>
namespace Error {
enum class Code;
static const Code None = static_cast<Code>(0);
}
class Foo{
public:
std::function<Error::Code()> Run();
};
福.cpp
#include "Foo.h"
#include <iostream>
std::function<Error::Code()> Foo::Run() {
return [&]() {
std::cout << "hellon";
return Error::None;
};
}
主.cpp:
#include "Foo.h"
namespace Error {
enum class Code {
None = 0,
Error = 1,
};
}
int main() {
Foo foo;
foo.Run()();
}
VC++ 14.0 中产生的错误如下所示:
Foo.obj : error LNK2001: unresolved external symbol "enum Error::Code __cdecl std::_Invoke_ret<enum Error::Code,class <lambda_813e82254384ef384f6a5fe34e885f01> &>(struct std::_Forced<enum Error::Code,0>,class <lambda_813e82254384ef384f6a5fe34e885f01> &)" (??$_Invoke_ret@W4Code@Error@@AAV<lambda_813e82254384ef384f6a5fe34e885f01>@@@std@@YA?AW4Code@Error@@U?$_Forced@W4Code@Error@@$0A@@0@AAV<lambda_813e82254384ef384f6a5fe34e885f01>@@@Z)
我相信这是用于实现std::function
的内部标准库功能。
此代码类似于我尝试使用的内部库的用法,该库共享工具的标准程序接口,但转发声明错误代码,以便可以自定义它们。 我相信这应该是基于 §7.2 的有效代码(请参阅此答案)枚举虽然是向前声明的,但应该是一个完整的类型,可用作返回值。 以下是标准中的相关位:
不透明枚举声明是当前范围内枚举的重新声明或新枚举的声明。[注意:由不透明枚举声明声明的枚举具有固定的基础类型,并且是完整类型。枚举器列表可以在以后的重新声明中使用枚举说明符提供。—尾注 ]
此代码有效吗? 如果是这样,有没有办法让VC++接受它?
是的,代码是有效的。
这当然似乎是MSVC错误。我能够用一个简单的代码示例重现这一点;
功能.cpp
#include <functional>
enum Code : int;
Code func2();
void func()
{
std::function<Code()> f2 { func2 };
}
主.cpp
enum Code : int {
Some = 0,
Error = 1,
};
Code func2() { return Some; }
int main() {}
错误仍然存在;
错误 LNK2019:未解析的外部符号"枚举代码__cdecl std::_Invoke_ret(struct std::_Forced,枚举代码 (__cdecl*&)(void))"(??_Invoke_ret@W4Code@@AEAP6A美元?AW41@XZ@std@@YA?AW4Code@@U?$_Forced@W4Code@@$0A@@0@AEAP6A?AW41@XZ@Z) 在函数"private: virtual enum Code __cdecl std::_Func_impl,enum Code>::_Do_call(void)" (?_Do_call@?$_Func_impl@P6A?AW4Code@@XZV?$allocator@H@std@@W41@$$V@std@@EEAA?AW4Code@@XZ)
该错误暗示了std::function<Code()>
的实例化问题,但两个翻译单元中再多的显式实例化都无法提供任何解决方案。
该错误似乎也不依赖于无作用域enum
与作用域enum class
。
目前唯一的解决方法似乎根本不使用不透明的枚举声明,而是为完整的枚举及其枚举器提供。
来自Microsoft连接 (2016-05-09);
此问题的修复程序已签入编译器源。此修复程序应显示在视觉C++的未来版本中。
以下是一些太大而无法评论的观察结果:
这确实是一个编译器错误,而不是标准库实现的错误。以下程序在VS2015 Update 1上重现相同的问题,而无需使用StdLib:
template<class T>
T create() {
return {};
}
enum class Code;
int main() {
create<Code>();
}
链接器抱怨未解析的符号:
enum Code __cdecl create<enum Code>(void)
- 如果省略返回值(将
T
替换为void
),链接器问题将消失。 - 显式指定基础类型时仍然存在问题。
- 如果将作用域枚举替换为无作用域枚举,则问题仍然存在。使用Microsoft的C++扩展(
/Ze
)时,我们不必指定底层类型。指定基础类型时没有任何变化。
我认为您应该在标头(.h)中声明None并在源文件(.cpp)中定义它
福.h
namespace Error {
extern const Code None;
}
福.cpp
namespace Error {
const Code None = static_cast<Code>(0);
}
有时枚举会被优化,并且没有实例或地址,尤其是您将其声明为静态变量。
- Visual Studio 2015:Extern "C" 和 "export" 关键字
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 试图在visual studio上用C++创建一个桌面应用程序
- 如何在MS Visual Studio 2019中运行QT UI
- 如何使用Visual Studio 2017在C++中为参数化对象数组使用唯一指针
- Visual Studio Code - C++ Debugger 無法啟動
- Visual Studio 2019:插入多个C++风格的单行注释
- Visual Studio Code "undefined reference to `WinMain@16'"
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- Visual Studio中的函数声明和函数定义问题
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- Visual Studio mkl_link_tool.exe链接错误
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 不同的Visual Studio版本中缺少.dll
- 用Visual Studio在C++中嵌入Julia
- Visual Studio 2017循环自动向量化问题
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- Visual Studio在尝试读取resource.txt文件时崩溃
- Visual Studio 2017 不允许我创建 C++ 专用模板