简体   繁体   中英

Function definition not found for a function declared inside unnamed namespace - how to resolve? (Visual Studio 2015)

I installed Visual Studio 2015 and found that some of my code (that hadn't any problems in VS 2013 ) now has got some errors indicated by green squiggles (which are supposed to be a new productivity feature ). Yet the code still compiles successfully.

Here's a quick example:

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 are the squiggles in question

在此输入图像描述

Moving the mouse over them tells me that

Function definition for 'test1' not found

Function definition for 'test2' not found


Somehow it turns out that only functions declared inside unnamed namespace trigger the squiggles.

How is it supposed to be resolved?

The green squiggles don't tell you that there's an error, they tell you that there's an opportunity for the new refactoring tools to do something. (Red squiggles indicate an error.) In this case, they're informing you that there is no definition matching the declaration of test2 , so the IDE is offering to generate one.

This happens to point out an error that was always there in the code, although Visual Studio might be behaving in a non-conforming manner.

So what happens? The problem is that the declarations in the unnamed namespace do not declare the same functions that you later define in the global namespace. The refactoring tools recognize this and offer to generate a definition for the declared functions.

However, the whole thing still compiles, due to the Microsoft compiler accepting two strictly illegal pieces of code. First, using the namespace prefix on the first declaration of a function is not allowed. The code in main then presumably calls the functions. As Alex M showed in his answer, GCC won't accept this either, since the call is ambiguous. The Microsoft compiler appears to accept it, either treating the definition as a definition matching the declaration in the unnamed namespace (remember, the tools of the IDE, IntelliSense and the refactory, used the more compliant EDG front-end, not the parser the actual compiler uses, which means that the refactory can say that the declaration has no definition, while the compiler treats the definition as matching the declaration), or just preferring the global version to the namespaced version.

It's easy to distinguish the two cases, by the way. Rearrange the code so that main comes before the function definitions. This will resolve the ambiguity in GCC, because only the namespaced function is declared (and not defined, so you should get a linker error). It will also lead to a linker error in the Microsoft compiler, if it just prefers the global version, but will still compile if it treats the declaration and definition as matching.

The solution to all this is very simple: when defining functions declared in the unnamed namespace, just reopen the namespace instead of trying to define the functions outside.

This compiles OK, with the light bulb you mentioned:

namespace
{
    void func();
}

void ::func() //Will not compile if 'void func()'
{}

int main()
{
    func();
}

But IntelliSense also outputs (in both cases):

Error (active) more than one instance of overloaded function "func"
matches the argument list: 

function "func()"
function "<unnamed>::func()"

Is this really what you want to do though? As n4527 at § 7.3.1.1 states:

An unnamed-namespace-definition behaves as if it were replaced by

 inline(opt) namespace unique { /* empty body */ } using namespace unique; namespace unique { namespace-body } 

where inline appears if and only if it appears in the unnamed-namespace-definition and all occurrences of unique in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the translation unit.

Which makes it clear why there are ambiguities going on. Just define your methods within your unnamed namespace, as they're different from anything else outside it.

For the record, GCC 5.2.0 and clang 3.6.0 won't agree to compile the code that MSVC compiled.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM