我遇到一个问题,下面的代码在GCC(4.8+测试)和Clang(3.4+测试)上编译,但不能在Visual Studio 2015(VC ++ 14.0)上编译。
foo.h中:
#include <functional>
namespace Error {
enum class Code;
static const Code None = static_cast<Code>(0);
}
class Foo{
public:
std::function<Error::Code()> Run();
};
Foo.cpp中
#include "Foo.h"
#include <iostream>
std::function<Error::Code()> Foo::Run() {
return [&]() {
std::cout << "hello\n";
return Error::None;
};
}
main.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
的内部std库函数。
此代码类似于我尝试使用的内部库的使用,它共享工具的标准程序接口,但转发声明错误代码,以便可以自定义它们。我认为这应该是基于§7.2的有效代码(参见this answer)枚举虽然是前向声明的,但应该是一个完整的类型并可用作返回值。以下是标准中的相关内容:
opaque-enum-declaration是对当前作用域中枚举的重新声明或新枚举的声明。 [注意:opaque-enum-declaration声明的枚举具有固定的底层类型,并且是完整类型。枚举器列表可以在稍后的重新声明中使用枚举说明符提供。 - 后注]
这段代码有效吗?如果是这样,是否有办法让VC ++接受它?
答案 0 :(得分:3)
是的,代码有效。
这肯定确实是MSVC的错误。我可以使用简单的代码示例重现这一点;
func.cpp
#include <functional>
enum Code : int;
Code func2();
void func()
{
std::function<Code()> f2 { func2 };
}
的main.cpp
enum Code : int {
Some = 0,
Error = 1,
};
Code func2() { return Some; }
int main() {}
错误仍然存在;
错误LNK2019:未解析的外部符号“enum Code __cdecl std :: _ Invoke_ret(struct std :: _ Forced,enum Code(__ cdecl *&amp;)(void))”(?? $ _ Invoke_ret @ W4Code @@ AEAP6A?AW41 @ XZ @std @@ YA?AW4Code @@ U?$ _强制@ W4Code @@ $ 0A @@ 0 @ AEAP6A?AW41 @XZ @ Z)在函数“private:virtual enum Code __cdecl std :: _ Func_impl,enum Code&gt;”中引用。 :: _ 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 Connect(2016-05-09);
此问题的修复程序已检入编译器源。修复程序应该出现在Visual C ++的未来版本中。
答案 1 :(得分:1)
以下是一些对评论来说太大的观察:
这确实是编译器错误,而不是标准库实现的错误。以下程序在不使用StdLib的情况下在VS2015 Update 1上重现相同的问题:
template<class T>
T create() {
return {};
}
enum class Code;
int main() {
create<Code>();
}
链接器抱怨未解析的符号:
enum Code __cdecl create<enum Code>(void)
T
替换为void
)。/Ze
)时,我们不必指定基础类型。指定基础类型时没有任何变化。答案 2 :(得分:-2)
我认为你应该在标题(.h)中声明无并在源文件(.cpp)中定义它
foo.h中
namespace Error {
extern const Code None;
}
Foo.cpp中
namespace Error {
const Code None = static_cast<Code>(0);
}
有时枚举将被优化,并且没有实例或地址,尤其是您将其声明为静态变量。