Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++0x confusion with using declarations

What should happen for this case:

struct A {
  void f();
};

struct B : virtual A {
  using A::f;
};

struct C : virtual A {
  using A::f;
};

struct D : B, C { 
  void g() {
    f();
  }
};

The line of interest is f(). Clearly the lookup of f according to 10.2 of the FDIS succeeds and finds A::f. However, what candidates will overload resolution consider? The spec says at 13.3.1p4:

For non-conversion functions introduced by a using-declaration into a derived class, the function is considered to be a member of the derived class for the purpose of defining the type of the implicit object parameter.

The intent of this is that for a single class, if such a class contains both own member functions and a using declaration bringing names of base class functions into scope, that during overload resolution all the function candidates have the same class type in their implicit object parameter. But what does this mean for the above example? Will the candidates be the following?

void F1(B&)
void F2(C&)
// call arguments: (lvalue D)

This appears to be wrong, because we only have one declaration in the lookup result set according to 10.2p7. How shall we interpret this??

like image 927
Johannes Schaub - litb Avatar asked Apr 16 '11 00:04

Johannes Schaub - litb


1 Answers

I think that since the lookup set resulting from 10.2/7 results in only one declaration, there's no function overloading present at all. 13.3.1/4 would only apply when/if the lookup set resulting from 10.2/7 contained two or more declarations.

Edit: Perhaps I wasn't as clear as I'd hoped. Even if f is overloaded in A, I think most of the same reasoning applies. Perhaps it's best to take things step by step. (Note, that in this case, I'm using the same S(f, X) notation as the standard, but since your most derived class is D, your S(f, D) corresponds to their S(f, C), and your S(f, B) ans S(f, C) correspond to its S(f, B1) and S(f, B2).

First s(f, D) is empty, because we have no declaration of f directly contained in D. Based on that, we get to 10.2/5.

In 10.2/6, we start by merging s(f, B) into S(f, D). Since s(f, D) is currently empty, we follow the second condition under the first bullet point, and S(f, D) becomes a copy of S(f, B).

Then we have to merge S(f, C) into S(f, D). In this case, each of the subobject members of S(f, C) is a subobject member of S(f, D). This satisfies the first condition of the first bullet point, so we leave S(f, D) unchanged, and the merge is complete.

At that point, there are no more base classes Bi to consider, so our S(f, D) = S(f, B). None of the declarations from S(f, C) is present in the final overload set at all.

Then, if S(f, B) contained two or more functions, we proceed to 13.3.1, and resolve the overload set -- but since the entire set came via B, the situation posited in the question simply doesn't exist.

like image 86
Jerry Coffin Avatar answered Nov 05 '22 23:11

Jerry Coffin