Namespaces
Variants
Actions

Talk:cpp/language/using declaration

From cppreference.com

I really liked this version: https://en.cppreference.com/mwiki/index.php?title=cpp/language/using_declaration&oldid=137430

And Cubbi removed nearly all of the comments and turned it back into this version, which is significantly different in clarity: https://en.cppreference.com/mwiki/index.php?title=cpp/language/using_declaration&oldid=137498

What comments do you think we can or should put back to make the important subtleties of the using usage more clear? Here are mine:

#include <iostream>
 
// Base class B
struct B
{
    virtualvoid f(int){std::cout<<"B::f\n";}
    void g(char)        {std::cout<<"B::g(char)\n";}
    void h(int)         {std::cout<<"B::h\n";}
protected:
    int m;// B::m is protected
    typedefint value_type;
};
 
// Derived class D
struct D : B
{
    using B::m;          // D::m is public
    using B::value_type;// D::value_type is public
 
    // Unnecessary usage of `using`:
    // `B::f` is already public and also publicly available as `D::f`,
    // and `D::f` below has the same signature as `B::f`above.
    using B::f;
    void f(int){std::cout<<"D::f\n";}// D::f(int) **overrides** B::f(int)
 
    // Necessary usage of `using`:
    // `B::g(char)` gets hidden by `D::g(int)`
    // unless it is explicitly exposed as `D::g(char)` here with `using B::g`.
    // Without this usage of `using B::g`, a char passed to a call of
    // `D::g(char)` would actually result in a call to the `D::g(int)`
    // function defined just below, since it otherwise hides `B::g(char)`,
    // and the `char` parameter would therefore be implicitly cast to `int`.
    using B::g;// exposes `B::g(char)` as `D::g(char)`, which is a completely
                // different function from `D::g(int)` defined next.
    void g(int){std::cout<<"D::g(int)\n";}// both g(int) and g(char) are
                                                // visible as members of D
 
    // Unnecessary usage of `using`:
    // `B::h` is already public and also publicly available as `D::h`,
    // and `D::h` below has the same signature as `B::h`above.
    using B::h;
    void h(int){std::cout<<"D::h\n";}// D::h(int) **hides** B::h(int)
};

In the example code, using B::f is totally useless and does absolutely nothing since the override of that virtual function would happen without it, and using B::h is totally useless and does nothing because the function definition of void h(int) then hides it, but (and this is really important) using B::g is absolutely necessary assuming the desired behavior is to keep void g(char) exposed from the parent function instead of having void g(int) from the child function hide it, thereby causing implicit casting to int if you pass a char to the child function. This is really tricky C++ behavior going on there that is begging for an explanation to even advanced users.

Comment out the three using usages I mention and you'll see only one of them does anything at all. So, what do you think we can do about this? Why not put some of those clarifying comments back in?

ERCaGuy (Gabriel Staples) (talk) 20:12, 25 January 2022 (PST)

The intent of the example (mostly borrowed from namespace.udecl/11) was to demonstrate the directly preceding sentence in the text ("hides or overrides"). As such, to be relevant, it needs to be three lines: one that hides, one that overrides, and one that adds to the as-if set of direct members of the derived class, with minimal wiring to make it compile. This is not the place for a tutorial on the use of the language feature or on virtual functions. --Cubbi (talk) 20:35, 25 January 2022 (PST)

In the section titled "Inheriting constructors",


 struct B1 { B1(int); }; struct D1 : B1 { using B1::B1; // The set of candidate inherited constructors is // 1. B1(const B1&) // 2. B1(B1&&) // 3. B1(int) // D1 has the following constructors: // 1. D1() 

D1() is not generated, because the base class B1 has no default constructor.



the page says "D1() = delete" which correctly describes D1's implicitly defined default constructor. --Cubbi (talk) 20:48, 25 January 2022 (PST)
close