http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47227

           Summary: GCC ignores conversion function template
                    specializatons if a derived class' conversion function
                    converts to the same type
           Product: gcc
           Version: 4.6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: schaub.johan...@googlemail.com


Unless I'm missing something, the following is ambiguous:

template<typename T1, typename T2>
struct A { };

struct base {
  template<typename T2, typename T1>
  operator A<T1, T2>();
};

struct derived : base {
  template<typename T1, typename T2>
  operator A<T1, T2>();
};

int main() {
  derived().operator A<int, int>();
}

However, GCC always wants to take the derived class version. 

The reason for ambiguity is:

A<param-#1#1, param-#1#2> is another type than A<param-#1#2, param-#1#1> (prior
to deduction. When collecting candidates, 14.5.2/6 says:

  "A specialization of a conversion function template is not found by name 
  lookup. Instead, any conversion function templates visible in the context of
  the use are considered. For each such operator, if argument deduction
succeeds
  (14.8.2.3), the resulting specialization is used as if found by name lookup."

In the context of the use, both functions templates are visible, so both are
sent to argument deduction. Deduction will succeed, so *the specialization is
used as if found by name lookup*. Name lookup cannot find declarations that are
hidden, so this quite clearly requires the above to be ambiguous, and doesn't
allow the base-class version to be "filtered out" later on. Hiding only takes
place prior to deduction:

template<typename T1, typename T2>
struct A { };

struct base {
  template<typename T1, typename T2>
  operator A<T1, T2>();
};

struct derived : base {
  template<typename T1, typename T2>
  operator A<T1, T2>();
};

int main() {
  derived().operator A<int, int>();
}

Now that is not ambiguous anymore, and will call the derived class version,
because in the context of the use, the base-class version is hidden (12.3/5 and
3/8).

Note that by constructing cases making the base-class version more specialized
than the derived class version, we could actually make this a rejects-valid
bug:

template<typename T1, typename T2>
struct A { };

struct base {
  template<typename T1, typename T2>
  operator A<T1*, T2>();
};

struct derived : base {
private:
  template<typename T1, typename T2>
  operator A<T1, T2>();
};

int main() {
  derived().operator A<int*, int>();
}

Comeau accepts this one just fine, while GCC rejects it, thinking the
base-version is hidden.

Reply via email to