我安装了Visual Studio 2015 ,发现我的一些代码(在VS 2013 中没有任何问题)现在已经出现了一些由绿色表示的错误squiggles(应该是新的生产力功能)。然而代码仍然成功编译。
这是一个简单的例子:
namespace
{
void test1(); // what once was OK in VS 2013,
void test2(); // is now marked with squiggles in VS 2015
}
namespace named
{
void test3(); // OK, no problem
}
void test1() { /*...*/ }
void ::test2() { /*...*/ }
void named::test3() { /*...*/ }
int main() { /*...*/ }
Theese是有问题的曲线
将鼠标移到它们上面告诉我
' test1'的功能定义找不到
' test2'的功能定义找不到
事实证明,只有在未命名的命名空间内声明的函数才会触发曲线。
如何解决?
答案 0 :(得分:3)
绿色曲线并没有告诉你这是一个错误,他们告诉你,新的重构工具有机会做某事。 (红色波形指示错误。)在这种情况下,他们会通知您没有与test2
的声明匹配的定义,因此IDE提供生成一个。
这恰好指出了代码中始终存在的错误,尽管Visual Studio可能会以不符合的方式运行。
那会发生什么?问题是未命名的命名空间中的声明不会声明您稍后在全局命名空间中定义的相同函数。重构工具认识到这一点并提供为声明的函数生成定义。
然而,由于Microsoft编译器接受两个严格非法的代码,整个事情仍在编译中。首先,不允许在函数的第一个声明中使用名称空间前缀。 main
中的代码可能会调用函数。正如Alex M在答案中所表明的那样,GCC也不会接受这个,因为这个电话是模棱两可的。 Microsoft编译器似乎接受它,要么将定义视为与未命名的命名空间中的声明匹配的定义(请记住,IDE的工具,IntelliSense和refactory,使用更兼容的EDG前端,而不是解析器实际编译器使用,这意味着重构可以说声明没有定义,而编译器将定义视为与声明匹配),或者只是将全局版本更改为命名空间版本。
顺便说一下,很容易区分这两种情况。重新排列代码,使main
位于函数定义之前。这将解决GCC中的歧义,因为只声明了命名空间函数(并且未定义,因此您应该收到链接器错误)。如果它只是喜欢全局版本,它也会导致Microsoft编译器中的链接器错误,但如果它将声明和定义视为匹配,它仍然会编译。
所有这一切的解决方案非常简单:在定义未命名的命名空间中声明的函数时,只需重新打开命名空间,而不是尝试在外部定义函数。
答案 1 :(得分:2)
用你提到的灯泡编译好了:
namespace
{
void func();
}
void ::func() //Will not compile if 'void func()'
{}
int main()
{
func();
}
但IntelliSense也输出(在两种情况下):
Error (active) more than one instance of overloaded function "func"
matches the argument list:
function "func()"
function "<unnamed>::func()"
这真的是你想要做的吗?正如第7.3.1.1节中的n4527所述:
unnamed-namespace-definition 的行为就好像被
取代一样inline(opt) namespace unique { /* empty body */ } using namespace unique; namespace unique { namespace-body }
当且仅当内联出现在内容中时,内联出现 unnamed-namespace-definition 并且翻译单元中所有出现的唯一标识都替换为相同的标识符, 标识符与翻译单元中的所有其他标识符不同。
这清楚地说明了为什么会出现歧义。只需在未命名的命名空间中定义方法,因为它们与其他任何命名空间不同。
为了记录,GCC 5.2.0和clang 3.6.0将不同意编译MSVC编译的代码。