3

Consider the following C++ code,

namespace {
  class ExprParentFinder {
    friend class CodeCompletionTypeContextAnalyzer;
  };
}

class CodeCompletionTypeContextAnalyzer {
public:
  CodeCompletionTypeContextAnalyzer() {}
};

int main() {
  CodeCompletionTypeContextAnalyzer TypeAnalyzer;
  return 0;
}

This compiles fine with Clang/GCC. However, MSVC chokes, and reports

1> ConsoleApplication2.cpp

1> consoleapplication2.cpp(29): error C2872: 'CodeCompletionTypeContextAnalyzer': ambiguous symbol

1> consoleapplication2.cpp(23): note: could be 'CodeCompletionTypeContextAnalyzer'

1> consoleapplication2.cpp(19): note: or '`anonymous-namespace'::CodeCompletionTypeContextAnalyzer'

Is CodeCompletionTypeContextAnalyzer TypeAnalyzer really ambiguous here from a C++ standards point of view, or is this an MSVC bug. If so, what's causing this error.

The work around is to change the code to

int main() {
  ::CodeCompletionTypeContextAnalyzer TypeAnalyzer;
  return 0;
}
Community
  • 1
  • 1
H Bellamy
  • 22,405
  • 23
  • 76
  • 114
  • Is the `CodeCompletionTypeContextAnalyzer` class ever forward-declared? – Dai Dec 16 '16 at 11:06
  • This is a minimum reproducible example - this code file is the only thing you need to demonstrate the ambiguity. – H Bellamy Dec 16 '16 at 11:07
  • How does the `ExprParentFinder` know about the existence of `CodeCompletionTypeContextAnalyzer` if it's not declared? – DrPepperJo Dec 16 '16 at 11:10
  • From friend class CodeCompletionTypeContextAnalyzer – H Bellamy Dec 16 '16 at 11:11
  • Oh sorry, I didn't know that classes could be forward declared in friend declarations ... interesting to know though! – DrPepperJo Dec 16 '16 at 11:13
  • 1
    What happens if you just change `friend class CodeCompletionTypeContextAnalyzer;` to `friend class ::CodeCompletionTypeContextAnalyzer;` ? – Richard Critten Dec 16 '16 at 11:27
  • http://rextester.com/l/cpp_online_compiler_visual – H Bellamy Dec 16 '16 at 11:30
  • Another work-arround is to forward-declare the class before the namespace. I suppose that the `friend` specification forward-declares the class in the actual namespace, if it is not known yet (howewer, currently I don't know whether or not it is C++ standard conformant). – EmDroid Dec 16 '16 at 12:01

1 Answers1

3

This is well-formed (i.e., MSVC bug) but unlikely to be what you actually want. [namespace.memdef]/3, footnote omitted:

If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup ([basic.lookup.unqual]) or qualified lookup ([basic.lookup.qual]).

friend class CodeCompletionTypeContextAnalyzer; declares CodeCompletionTypeContextAnalyzer to be a member of the unnamed namespace, but that name is not visible to name lookup.

Then, class CodeCompletionTypeContextAnalyzer { /* ... */ }; declares (and defines) a different class also called CodeCompletionTypeContextAnalyzer as a member of the global namespace; this class is not a friend of ExprParentFinder.

Because the unnamed namespace's CodeCompletionTypeContextAnalyzer isn't visible to name lookup, the only CodeCompletionTypeContextAnalyzer that can be found is the second one, and there is no ambiguity.

T.C.
  • 133,968
  • 17
  • 288
  • 421