2

We know that a 'using declaration' for a namespace's member name in a scope where another entity is defined there with the same name, causes a compile time error: "symbol x is already defined".

The error is detected at the point the 'using declaration' appears not at use point like a 'using directive'.

A using declaration in a class scope allows only exposing a base class member name.

Here is an example:

#include <iostream>
using namespace std;

struct Foo{
    Foo(int x) : x_(x){}
    int x_ = 0;
};

struct Bar{
    Bar(int y) : y_(y){}
    int y_ = 0;
};

struct FooBar : Foo, Bar{
    using Foo::Foo; // inheriting Foo's ctors
    using Bar::Bar; // inheriting Bar's ctors

    int x_ = 10;
//    using Foo::x_; // error detected here
};

int main(){
    FooBar fb(5); // error detected here

}

As you can see above the using declaration for Foo::x_ causes a compile-time error at the point the using appears and it is OK.

But the using declaration for base classes Foo and Bar constructors don't issue an error until the usage in main?!!

  • Normally FooBar inherits Foo(int); so when using Bar::Bar; appears normally the compiler complains but the code works fine until I try to use that constructor. FooBar(int).

After inheriting all the constructors, the compiler defines a derived class ctor and make it call its base class one passing in its parameters to it so it is as if we wrote:

struct FooBar : Foo, Bar{
        FooBar(int x) : Foo(x){}
        FooBar(int x) : Bar(x){}
//...
};

So why the compiler allows such bug? and wait until the use of that ctor to flag ambiguity??

  • It looks to me that a using declaration in such case undergoes the same thing like a using directive.
ma1169
  • 659
  • 1
  • 8
  • 26
Itachi Uchiwa
  • 3,044
  • 12
  • 26
  • your said " the using declarations for base classes Foo and Bar constructors don't issue an error until the usage in main?!!" well they cause an error, comment the following two line FooBar fb(5); and int x_ = 10; you will get bar constructor already inherited from foo at using Bar::Bar; – ma1169 Apr 12 '21 at 19:32
  • No and that is why I've posted this question. – Itachi Uchiwa Apr 12 '21 at 19:43
  • No?? do you mean that , when you comment these two lines, you don't get an error?? if you don't get an error it must be a compiler settings – ma1169 Apr 12 '21 at 19:48
  • https://godbolt.org/z/afx6Ts5fx – Itachi Uchiwa Apr 12 '21 at 19:57
  • @ma1169: Yes sure. I've already said this. I am using gcc and clang. – Itachi Uchiwa Apr 12 '21 at 20:03

1 Answers1

1

It is a general (though not universal) principle of C++ that a prefix of a program is valid if and only if there is some valid completion of it that uses the declarations in the prefix. This is why it’s not an error to declare an unused variable: it could be used, and it’s “too late” to reject it later if it’s not. Here, that principle is generalized a bit to say that, because overload resolution can usually distinguish between functions from different namespaces or base classes, there is no check for conflict at all.

Not so for variables, since you can’t possibly use the ambiguous combination. Also not so if one of the conflicting functions declarations is a direct member and a sibling of the using-declaration: in that case, you can’t possibly use the function you declared, so you are presumed not to have meant it.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76