This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 110b. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2023-01-15


416. Class must be complete to allow operator lookup?

Section: 12.2.2.3  [over.match.oper]     Status: CD1     Submitter: Greg Comeau     Date: 22 May 2003

[Voted into WP at October 2004 meeting.]

Normally reference semantics allow incomplete types in certain contexts, but isn't this:

  class A;

  A& operator<<(A& a, const char* msg);
  void foo(A& a)
  {
    a << "Hello";
  }

required to be diagnosed because of the op<<? The reason being that the class may actually have an op<<(const char *) in it.

What is it? un- or ill-something? Diagnosable? No problem at all?

Steve Adamczyk: I don't know of any requirement in the standard that the class be complete. There is a rule that will instantiate a class template in order to be able to see whether it has any operators. But I wouldn't think one wants to outlaw the above example merely because the user might have an operator<< in the class; if he doesn't, he would not be pleased that the above is considered invalid.

Mike Miller: Hmm, interesting question. My initial reaction is that it just uses ::operator<<; any A::operator<< simply won't be considered in overload resolution. I can't find anything in the Standard that would say any different.

The closest analogy to this situation, I'd guess, would be deleting a pointer to an incomplete class; 7.6.2.9 [expr.delete] paragraph 5 says that that's undefined behavior if the complete type has a non-trivial destructor or an operator delete. However, I tend to think that that's because it deals with storage and resource management, not just because it might have called a different function. Generally, overload resolution that goes one way when it might have gone another with more declarations in scope is considered to be not an error, cf 9.9 [namespace.udecl] paragraph 9, _N4868_.13.8.4 [temp.nondep] paragraph 1, etc.

So my bottom line take on it would be that it's okay, it's up to the programmer to ensure that all necessary declarations are in scope for overload resolution. Worst case, it would be like the operator delete in an incomplete class -- undefined behavior, and thus not required to be diagnosed.

12.2.2.3 [over.match.oper] paragraph 3, bullet 1, says, "If T1 is a class type, the set of member candidates is the result of the qualified lookup of T1::operator@ (12.2.2.2.2 [over.call.func])." Obviously, that lookup is not possible if T1 is incomplete. Should 12.2.2.3 [over.match.oper] paragraph 3, bullet 1, say "complete class type"? Or does the inability to perform the lookup mean that the program is ill-formed? 6.3 [basic.def.odr] paragraph 4 doesn't apply, I don't think, because you don't know whether you'll be applying a class member access operator until you know whether the operator involved is a member or not.

Notes from October 2003 meeting:

We noticed that the title of this issue did not match the body. We checked the original source and then corrected the title (so it no longer mentions templates).

We decided that this is similar to other cases like deleting a pointer to an incomplete class, and it should not be necessary to have a complete class. There is no undefined behavior.

Proposed Resolution (October 2003):

Change the first bullet of 12.2.2.3 [over.match.oper] paragraph 3 to read:

If T1 is a complete class type, the set of member candidates is the result of the qualified lookup of T1::operator@ (12.2.2.2.2 [over.call.func]); otherwise, the set of member candidates is empty.