3

Why do I have to reintroduce the name of a function having some of its overloads deleted ?

#include <string>

struct A
{
    void f(int) {}
    void f(double) {}
    void f(const std::string&) {}
};

struct B : public A
{
    using A::f; // needed to compile : why ?
    void f(int)=delete;
    void f(double)=delete;
};

int main()
{
    B b;
    b.f(std::string("toto"));
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
SR_
  • 874
  • 13
  • 31

3 Answers3

3

A single declaration of f in the B class hides all declarations of f from the base A class.

And even marking the functions as deleted is considered a declaration.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

These records within the structure B

void f(int)=delete;
void f(double)=delete;

are declarations that hide the declarations with the same name f in the base structure A.

So the using declaration in B

using A::f; // needed to compile : why ?

makes all functions with the name f declared in A visible in the structure B.

Consider the following demonstrative program where in one case there is no using declaration and in the second case there is a using declarations.

#include <iostream>

int main() 
{
{   
    struct A
    {
        void f( char ) const
        {
        std::cout << "A::f( char ) const\n";
        }
    };

    struct B : A
    {
        void f( int ) const
        {
            std::cout << "B::f( int ) const\n";
        }
    };


    B b;
    
    b.f( 'A' );
}

std::cout << '\n';

{   
    struct A
    {
        void f( char ) const
        {
        std::cout << "A::f( char ) const\n";
        }
    };

    struct B : A
    {
        using A::f;
        void f( int ) const
        {
            std::cout << "B::f( int ) const\n";
        }
    };


    B b;
    
    b.f( 'A' );
}

    return 0;
}

The program output is

B::f( int ) const

A::f( char ) const
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

It's legalistic, but at least it's consistent.

I think you're thinking that when a function is overridden in a derived class, the mechanism there is that the function from the base class, or at least its identifier, is conceptually imported into the derived class and then overridden. But really, what's happening is that code which calls b.f never even sees A::f, because the lookup succeeds before it gets there. All that happens before overload resolution takes place.

So if you want to have access to the various overloads from A alongside those of B (including the deleted ones), you need to import them into B, so the compiler doesn't give up before seeing them.

Sneftel
  • 40,271
  • 12
  • 71
  • 104