Namespaces
Variants
Views
Actions

Using-declaration

From cppreference.com
< cpp‎ | language
Revision as of 06:42, 16 April 2013 by Cubbi (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 

Introduces a name that is defined elsewhere into the declarative region where this using-declaration appears.

using typename(optional) Template:sparam Template:sparam ; (1)
using :: Template:sparam ; (2)
Template:sparam - a sequence of names and scope resolution operators ::, ending with a scope resolution operator. A single :: refers to the global namespace.
Template:sparam - an id-expression
Template:sparam - the keyword typename may be used as necessary to resolve dependent names, when the using-declaration introduces a type

Contents

Explanation

Using-declarations are used for three purposes:

In namespace and block scope

Using-declaration introduces a member of another namespace into current namespace or function scope

#include <iostream>
using std::string;
int main()
{
    std::string str = "Example";
    using std::cout;
    cout << str;
}

See namespace for details.

In class definition

1) Using-declaration introduces a member of a base class into the derived class definition, such as to expose a protected member of base as public member of derived. In this case, Template:sparam must name a base class of the one being defined. If the name is the name of an overloaded member function of the base class, all base class member functions with that name are introduced. If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the injected base class name.
#include <iostream>
struct B {
    virtual void f(int) { std::cout << "B::f\n"; }
    void g(char)        { std::cout << "B::g\n"; }
    void h(int)         { std::cout << "B::h\n"; }
 protected:
    int m; // B::m is protected
    typedef int value_type;
};
 
struct D : B {
    using B::m; // D::m is public
    using B::value_type; // D::value_type is public
 
    using B::f;
    void f(int) { std::cout << "D::f\n"; } // D::f(int) overrides B::f(int)
    using B::g;
    void g(int) { std::cout << "D::g\n"; } // both g(int) and g(char) are visible
                                           // as members of D
    using B::h;
    void h(int) { std::cout << "D::h\n"; } // D::h(int) hides B::h(int)
};
 
int main()
{
    D d;
    B& b = d;
 
//    b.m = 2; // error, B::m is protected
    d.m = 1; // protected B::m is accessible as public D::m
    b.f(1); // calls derived f()
    d.f(1); // calls derived f()
    d.g(1); // calls derived g(int)
    d.g('a'); // calls base g(char)
    b.h(1); // calls base h()
    d.h(1); // calls derived h()
}

Output:

D::f
D::f
D::g
B::g
B::h
D::h
2) (since C++11) If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), constructors of that base class are inherited, according to the following rules:
a) A set of inheriting constructors' is composed of
*) All non-template constructors of the base class
*) For each constructor with default arguments or the ellipsis parameter, all constructor signatures that are formed by dropping the ellipsis and omitting default arguments from the ends of argument lists one by one
*) All constructor templates of the base class
*) For each constructor template with default arguments or the ellipsis, all constructor signatures that are formed by dropping the ellipsis and omitting default arguments from the ends of argument lists one by one
b) All inherited constructors that aren't the default constructor or the copy/move constructor and whose signatures do not match user-defined constructors in the derived class, are implicitly declared in the derived class. The default parameters are not inherited:
struct B1 {
    B1(int);
};
struct D1 : B1 {
    using B1::B1;
// The set of inherited constructors is 
// 1. B1(const B1&)
// 2. B1(B1&&)
// 3. B1(int)
 
// D1 has the following constructors:
// 1. D1()
// 2. D1(const D1&) 
// 3. D1(D1&&)
// 4. D1(int) <- inherited
};
 
struct B2 {
    B2(int = 13, int = 42);
};
struct D2 : B2 {
    using B2::B2;
// The set of inherited constructors is
// 1. B2(const B2&)
// 2. B2(B2&&)
// 3. B2(int = 13, int = 42)
// 4. B2(int = 13)
// 5. B2()
 
// D2 has the following constructors:
// 1. D2()
// 2. D2(const D2&)
// 3. D2(D2&&)
// 4. D2(int, int) <- inherited
// 5. D2(int) <- inherited
};
The inherited constructors are equivalent to user-defined constructors with an empty body and with a member initializer list consisting of a single Template:sparam, which forwards all of its arguments to the base class constructor.

Notes

Only the name explicitly mentioned in the using-declaration is transferred into the declarative scope: in particular, enumerators are not transferred when the enumeration type name is using-declared.

A using-declaration cannot refer to a template-id, to a namespace, to a scoped enumerator, to a destructor of a base class or to a specialization of a member template for a user-defined conversion function.

If a using-declaration brings the base class assignment operator into derived class, whose signature happens to match the derived class's copy-assignment or move-assignment operator, that operator is hidden by the implicitly-declared copy/move assignment operator of the derived class.

If two using-declarations inherit the constructor with the same signature (from two direct base classes), the program is ill-formed.