c++gccoverloadingicc

Combining the 'using' directive with partial overloading: gcc feature or intel bug?


I wish to use a set of libraries written in C++ with the Intel compilers. I've attached sample code which demonstrates the problem. There are many places in the libraries where they make use of combining the 'using' directive with partial overloading (e.g., I want to use the foo(void) method from the base class but reimplement the second version fo foo in the derived class). gcc does not have a problem but intel does.

#include <iostream>
template <class F>
struct Interface
  {
     static const F f=10;
  };

template <class F>
struct Base : public Interface<F>
  {
     void foo (void) { std::cout << "void" << std::endl; }
     template <class FF>
     void foo (Interface<FF> &ii) { std::cout << "F : " << ii.f << std::endl; }
  };

template <class F,int i>
struct Derived : public Base<F>
  {
    // void foo (void) { Base<F>::foo(); }  // works fine
    using Base<F>::foo;                     // gives error
    template <class FF>
    void foo (Interface<FF> &ii) { std::cout << "Derived<" << i << "> F : " << ii.f << std::endl; }
 };

int main (void)
  {
    Derived<double,10> o;
    o.foo();                  // ok
    o.foo (o);                // problem
  }

The compiler error that icc gives is:

test.cc(30): error: more than one instance of overloaded function "Derived<F, i>::foo    [with F=double, i=10]" matches the argument list:
        function template "void Base<F>::foo(Interface<FF> &) [with F=double]"
        function template "void Derived<F, i>::foo(Interface<FF> &) [with F=double, i=10]"
        argument types are: (Derived<double, 10>)
        object type is: Derived<double, 10>
o.foo (o);                // problem
  ^

compilation aborted for test.cc (code 2)

If you remove the line

using Base<F>::foo;

and replace it with the line

void foo (void) { Base<F>::foo(); }

everything works fine.

My question is does anyone know if this is a special gcc feature or icc bug? Or is there another work around which would not involve changing the code?

This is with g++.real (Ubuntu 4.4.3-4ubuntu5) 4.4.3 and icc (ICC) 12.0.2 20110112.


Solution

  • For C++11, the relevant Standard quote can be found in

    7.3.3 The using declaration [namespace.udecl]

    14/ If a function declaration in namespace scope or block scope has the same name and the same parameter types as a function introduced by a using-declaration, and the declarations do not declare the same function, the program is ill-formed.

    This supports the EDG-based compilers. However, a special case is meant for use in classes:

    15/ When a using-declaration brings names from a base class into a derived class scope, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). [ Note: For using-declarations that name a constructor, see 12.9. —end note ] [ Example:

    struct B {
      virtual void f(int);
      virtual void f(char);
      void g(int);
      void h(int);
    };
    
    struct D : B {
      using B::f;
      void f(int); // OK: D::f(int) overrides B::f(int);
    
      using B::g;
      void g(char); // OK
    
      using B::h;
      void h(int); // OK: D::h(int) hides B::h(int)
    };
    
    void k(D* p)
    {
      p->f(1); // calls D::f(int)
      p->f(’a’); // calls B::f(char)
      p->g(1); // calls B::g(int)
      p->g(’a’); // calls D::g(char)
    }
    

    —end example ]

    Therefore, in C++11, it seems Comeau and Intel are wrong. I do not know whether these rules equally applied in C++03