Sobrecarga en C ++. Parte I. Funciones y plantillas de sobrecarga


C ++ es un lenguaje complejo e interesante, puede mejorarlo casi toda su vida. En algún momento, quería estudiarlo de la siguiente manera: tomar algún aspecto del lenguaje, posiblemente bastante limitado, y tratarlo de la manera más profunda y detallada posible. Este enfoque fue ampliamente estimulado por los notables libros de Scott Meyers, Herb Sutter y Stephen Dewhurst. Cuando se acumuló una cierta cantidad de materiales, decidí presentarles Khabrovchan. Así que estaba esta serie, que llamé "C ++, cavando en profundidad". La serie está marcada como Tutorial, pero todavía se centra no en principiantes, sino en el nivel intermedio. El primer tema es la sobrecarga en C ++. El tema resultó ser muy extenso y obtuvimos tres artículos. El primer artículo trata sobre la sobrecarga de funciones y plantillas, el segundo sobrecarga de operadores y el tercero sobrecarga de operadoresnew/delete. Entonces, comencemos a cavar.



Tabla de contenido


Tabla de contenido

  
  1.
    1.1.
    1.2.
    1.3.
      1.3.1.
      1.3.2.
      1.3.3.
    1.4.
      1.4.1. using-
      1.4.2. using-
      1.4.3. using-
      1.4.4. ,
  2.
    2.1. «»
    2.2.
    2.3.
    2.4.
    2.5.
      2.5.1.
      2.5.2. SFINAE
      2.5.3.
      2.5.4.
    2.6. «»
      2.6.1. ,
      2.6.2. Rvalue
      2.6.3.
  3. ,
    3.1.
    3.2.
    3.3.
    3.4.
    3.5.
  4.
  
     . Visitor
     .
  




IntroducciĂłn


En un sentido amplio, la sobrecarga es la capacidad de usar simultáneamente varias funciones con el mismo nombre. El compilador los distingue por el hecho de que tienen un conjunto diferente de parámetros. En los puntos de llamada, el compilador analiza los tipos de argumentos y determina qué función particular debe llamarse. En la literatura en ruso, a veces se puede encontrar el término "compartir", pero no parece haber arraigado.


La sobrecarga es compatible con muchos lenguajes de programaciĂłn, consideraremos solo C ++ 17.



1. Disposiciones generales



1.1. Funciones sobrecargadas


( ) (overloaded), (scope) . , (=delete) .


void Foo();
char Foo(); // 
void Foo(int x);
void Foo(int x) noexcept;  // 
void Foo(double x);
void Foo(double) = delete; // 

, .


, . (decay) ,


void Foo(int x[4]);
void Foo(int x[]);
void Foo(int *x);

, .


.


, , const ( volatile),


void Foo(int x);
void Foo(const int x);

, .



1.2.


. (lookup) , (candidate functions). (template argument deduction). ( ). , . , . , , , « » (match the arguments most closely). (overload resolution). , , (ambiguous call to overloaded function). :


void Foo(float x);
void Foo(double x);

Foo("meow") , Foo(42) , , Foo(3.14f) Foo(3.14) .


(overload resolution rules) ( , ), , . .


« » : - . .


— . ( private protected). ( =delete). , . , , .



1.3.


, . . , . . , , , . () .


, . . , . , , . (hide) . , , , , , .



1.3.1.


, , . .


class X {/* ... */};
// ...
X x;
x.Foo();
X::Foo(42);

X. X.


namespace N {/* ... */}
// ...
N::Foo();

N, .


::Foo();

, .


«» .


, , .


( ), , .




{
    Foo();
}

. (, , . .) , ( -) .



1.3.2.


.


class B
{
// ...
public:
    void Foo(int x);
};

class D : public B
{
// ...
public:
    D();
    void Foo(double x);
};
// ...
D d;
d.Foo(42);

Foo, ? D::Foo(double), B::Foo(int) . ( D), , ( B) . D::Foo(double) . D::Foo(double) , , B::Foo(int) , . , D Foo, B B::Foo(int).


. C++ , , . . , . ( , .)



1.3.3.


C++, . ( ), :


{
    void Foo();
    void Foo(int x);
// ...
    Foo(42);
// ...
}

, , , C++ . , , , . , . ( ), ( - ) .



1.4.


using- using-. , , .


, , , , , .



1.4.1. using-


:


class B
{
// ...
public:
    void Foo(int x);
};
class D : public B
{
// ...
public:
    using B::Foo;
    void Foo(double x);
};
// ...
D d;
d.Foo(42);

Foo B, B::Foo(int).



1.4.2. using-


using- , . using- . , , using-, , . :


namespace N
{
    void Foo(int x);
}

void Foo(const char* x);
// ...
void Test()
{
    using N::Foo; //  Foo(const char*)
    Foo(42);      // OK, N::Foo(int x)
    Foo("meow");  // , Foo(const char*) 
}

, Foo , using- :


namespace N
{
    void Foo(int x);
}

void Foo(const char* x);
// ...
using N::Foo;
void Test()
{
    Foo(42);      // OK, N::Foo(int)
    Foo("meow");  // OK, Foo(const char*)
}


1.4.3. using-


N.


using namespace N;

using-. N N::. N, using- (, using-, ). , , using- , .


, , , , . ( using-.)


namespace
{
    void Foo(int x);
}

void Foo(const char* x);
// ...
Foo(42);     // OK, Foo(int),   
Foo("meow"); // OK, Foo(const char*)


1.4.4. ,


, . :


namespace N
{
    class X {/* ... */};
    void Foo(const X& x);
}

( N):


N::X x;
Foo(x);

N , , N::Foo(const X&). , (argument depended lookup, ADL), . ADL , .



2.


, .



2.1. «»


C++ . , . , , . : , , .


bool. bool int bool. . bool int.


void Foo(int x);
void Foo(bool x);
// ...
int x = 6, y = 5;
Foo(x == y); // Foo(bool)
Foo(x = y);  // Foo(int)



void Foo(bool x, int y);
void Foo(int x, bool y);

, :


Foo(1, 2);

, . int.


enum Qq { One = 1, Two };
void Foo(int x);
void Foo(Qq x);
// ...
Foo(One); // Foo(Qq)
Foo(42);  // Foo(int)

, , int long .


void Foo(int x);
void Foo(long x);
// ...
Foo(42);  // Foo(int)
Foo(42L); // Foo(long)

. . , , . :


void Foo(long x);
void Foo(long long x);

void Foo(float) = delete;
void Foo(double) = delete;
void Foo(long double) = delete;


2.2.


C++11 — std::nullptr_t nullptr. .


void Foo(int x);
void Foo(void* x);
// ...
Foo(0);       // Foo(int)
Foo(nullptr); // Foo(void*)

C++98


Foo((void*)0);

. nullptr , nullptr.


void Foo(void* x);
void Foo(std::nullptr_t);
// ...
void* x = nullptr;
Foo(x);       // Foo(void*)
Foo(nullptr); // Foo(std::nullptr_t)

.



2.3.


++11 (uniform initialization) — std::intializer_list<>. , , . . .


  1. — {}, . , .
  2. , std::intializer_list<>. std::intializer_list<>, , . , std::intializer_list<>, ( ), .

std::vector<T>, std::intializer_list<T>.


:


std::vector<int> v1(3, 1), v2{3, 1};

v1 — 3 1. v2 — 2 3 1, std::intializer_list<int>, , .


:

std::vector<const char*> u1(3, "meow"), u2{3, "meow"};

u1 u2 , 3. u2 std::intializer_list<const char*> , u1.


:


std::vector<bool> b1(3, true), b2{3, true};

b1 3 , true. b2 , std::intializer_list<bool> int bool.


[Meyers2].



2.4.


, ... , , . .



2.5.


, , . — c .


. ( , ), .



2.5.1.


. , . , . , .


, , . , . , , . [Sutter2].


C++11 (variadic templates). , , , .



2.5.2. SFINAE


, , . :


template<typename T>
void Foo(const T* x);
// ...
Foo(42);

, , , , , «» . SFINAE, Substitution Failure is not an Error ( ).



2.5.3.


, .


void Foo(int x); //  
template<typename T>
void Foo(T x); //  1
template<>
void Foo<double>(double x); //    1  double
template<>
void Foo<const char*>(const char* x); //    1  const char*
template<typename T>
void Foo(const T* x); //  2,     1
template<typename T>
class U {/* ... */};
template<typename T>
void Foo(U<T> u); //  3,     1

, :


Foo(42);       // #1 —  
Foo(3.14);     // #2 —    1  double
Foo(42L);      // #3 —   1  long
Foo("meow");   // #4 —   2  char
Foo(U<int>()); // #5 —   3  int

: 1 int. .


, double int. : 1 double 1 double, .


, long int. : 1 long, .


, : 1 const char* 2 char. 2 , , 1 const char* .


, : 1 U<int> 3 int. 3 .



2.5.4.


:


void Foo(int x);     //  
template<typename T> // 
void Foo(T x);

int, int&, const int, const int&, (long, short, unsigned int, etc.) . , (greedy). , , , . . , . — (template disabling). :


template<
    typename T,
    typename S = std::enable_if_t<!std::is_integral<T>::value>>
void Foo(T x);

SFINAE , , .


, , , :


template<typename T> //  
void FooInt(T x);
template<typename T> //  
void FooEx(T x);
// C++17
template<typename T>
void Foo(T x)
{
    if constexpr (std::is_integral<T>::value)
    {
        FooInt(x);
    }
    else
    {
        FooEx(x);
    }
}
// C++11
template<typename T>
void Foo(T x)
{
    std::is_integral<T>::value
        ? FooInt(x)
        : FooEx(x);
}

<type_traits>.



2.6. «»


«» : , , , rvalue .


. :


  1. lvalue — ;
  2. () lvalue — ;
  3. rvalue — lvalue, std::move();
  4. () rvalue — .

— .


, .
:


void Foo(T& x);

lvalue.


rvalue-:


void Foo(T&& x);

rvalue.


:


void Foo(const T& x);
void Foo(T x);

.



2.6.1. ,


:


void Foo(T& x);
void Foo(const T& x);

lvalue ( ), .


:


void Foo(T& x);
void Foo(T x);

rvalue , lvalue .


:


void Foo(const T& x);
void Foo(T x);

.


- const this.


class X
{
public:
    X();
    void Foo();       // this   X*
    void Foo() const; // this   const X*
    void DoSomething() const;
    void DoSomethingElse();
// ...
};
void X::DoSomething() const
{
// ...
    Foo(); // Foo() const
// ...
}
void X::DoSomethingElse()
{
// ...
    Foo(); // Foo()
// ...
}
// ...
X x;
x.Foo();  // Foo()
const X cx;
cx.Foo(); // Foo() const

H - rvalue , rvalue. rvalue .


class X
{
public:
    X();
    void Swap(X& other) noexcept;
// ...
};
// ...
X x;
// ...
X().Swap(x); // OK
x.Swap(X()); // ,      

rvalue . , . rvalue . ( , rvalue .) rvalue . , , , , . [Sutter1].



2.6.2. Rvalue


C++11 . — rvalue-. Rvalue- C++ , , rvalue-. , , «» .


:


void Foo(T&& x);
void Foo(const T& x);

rvalue ( ), .


:


void Foo(T&& x);
void Foo(T x);

lvalue , rvalue , .


:


void Foo(T&& x);
void Foo(T& x);

rvalue , lvalue , .


, — rvalue, — , , . ( .) , , , .


++11, rvalue- — -. (lvalue/rvalue) this.


class X
{
public:
    X();
    void Foo() &;  // this   lvalue
    void Foo() &&; // this   rvalue
// ...
}; 
// ...
X x;
x.Foo ();  // Foo() &
X().Foo(); // Foo() &&

: rvalue- lvalue. , rvalue-, lvalue , - , std::move(), rvalue- .



2.6.3.




template<typename T>
void Foo(T&& x);

rvalue-, (universal reference). . lvalue x T&, const T&, rvalue T&&. x lvalue, - std::forward<T>(), , T&&, rvalue. (greedy), . , 2.5. (perfect forwarding) . [Meyers2].



3. ,



3.1.


C++ , - (, , , ), . (incomplete declaration), (forward declaration). . .


class X; //   X
class Y; //   Y
void Foo(X* x);
void Foo(Y* y);
// ...
X* px;
// ...
Foo(px); // void Foo(X* x);

X , .



3.2.


.


void Foo(int x);
void Foo(const char* x);
// ...
void (*pF)(int) = Foo; // Foo(int)

, . (, ) , ADL .


namespace N
{
    class X {/* ... */};
    void Foo(const X& x);
}
// ...
void (*pF)(const N::X&) = Foo;    // 
void (*pF)(const N::X&) = N::Foo; // OK
using N::Foo;
void (*pF)(const N::X&) = Foo;    // OK

.


void Foo(int x);
void Foo(const char* x);
// ...
auto pf = static_cast<void(*)(int)>(Foo); // Foo(int)

ADL .


, auto.


auto pf = Foo;

Foo , , pf Foo. Foo, , .


, (). std::function<>, , , std::sort(). .


- - .


class X
{
// ...
    void Foo(int a);
    void Foo(const char* a);
};
// ...
void (X::*pF)(int) = &X::Foo; // X::Foo(int)


3.3.


.



void Foo(int x);
void Foo() { Foo(0); }



void Foo(int x = 0);

, Foo(), . , .


void (*pF1)(int) = Foo; // OK
void (*pF0)() = Foo;    // , Foo    

.


, , .



3.4.


. , , , , , . («» , . 1.3). [Dewhurst]. — . , ( , - ), , . . , Visitor.



3.5.


, , — , . , . , .


, . -, std::input_iterator_tag. (typedef) — iterator_category. , -, iterator_category, , . :


void DisplayIterCat(std::input_iterator_tag tag)
{
    std::cout << "Input iterator\n";
}
//  DisplayIterCat   -
template<class Iter>
void DisplayIterCat(Iter it)
{
    DisplayIterCat(typename Iter::iterator_category());
}

typename. , iterator_category Iter.


C++ , , . :


template<typename T, T val>
struct integral_constant;

T T, , . :


typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

, , .


, . :


sizeof(Foo(expr))

. expr , . , Foo , Foo . .


C++17 if constexpr (), , . ( ) .



4.


— , . , .


, . , . , .


, .


— .





. Visitor


A, V


void DoDblDispatchOper(A* a, V* v);

a v , , a, v, . . , , . Visitor — [GoF].


, IAcceptor IVisitor.


class IVisitor;
class IAcceptor
{
public:
    virtual void Accept(IVisitor* visitor) = 0;
// ...
};
class A1;
class A2;
// ...
class IVisitor
{
public:
    virtual void Visit(A1* a) = 0;
    virtual void Visit(A2* a) = 0;
// ...
};
class A1 : public IAcceptor 
{
    void Accept(IVisitor* visitor) override
    {
        visitor->Visit(this);
    }
// ...
};
class A2 : public IAcceptor
{
    void Accept(IVisitor* visitor) override
    {
        visitor->Visit(this);
    }
// ...
};
// ...
class V1 : public IVisitor {/* ... */};
class V2 : public IVisitor {/* ... */};
// ...

IVisitor Visit() , IAcceptor. Visit() , .




void IAcceptor::Accept(IVisitor* visitor);

, :


visitor->Visit(this);

this , Visit(). Visit(), visitor.


void DoDblDispatchOper(IAcceptor* acceptor, IVisitor* visitor)
{
    acceptor->Accept(visitor);
}

Voila. .



.


- . — ( ) .


template<typename T>
void swap(T& a, T& b);

, , . . , std::swap() , , . , std::swap(), , , . , .


1. - Swap() ( ), .


class X
{
public:
    void Swap(X& other) noexcept;
// ...
};

, , C++11 noexcept.


2. , X ( , ), (-) swap() ( ):


inline void swap(X& a, X& b) noexcept { a.Swap(b); }

, ADL, std::swap() .


3. std::swap() X


namespace std
{
    template<>
    void swap<X>(X& a, X& b) noexcept { a.Swap(b); }
};

std , - . std.


, ? — . , , .


namespace N
{
    template<typename T>
// ...
    T x, y;
// ...
    swap(x, y);
// ...

, T swap(), , . std::swap() , , .



:


std::swap(x, y);

swap() std::swap() — . .


:


using std::swap;
swap(x, y);

, . std::swap(), . std::swap(). std::swap() .


, ( std)


std::swap(x, y);



swap(x, y);

[Meyers1] , .


, .


template<typename T>
class X
{
// ...
public:
    void Swap(X& other) noexcept;
};
template<typename T>
void swap(X<T>& a, X<T>& b) noexcept { a.Swap(b); }

std::swap() , std , , , , .


friend swap() :


template<typename T>
class X
{
// ...
    void Swap(X& other) noexcept;
    friend void swap(X& a, X& b) noexcept { a.Swap(b); }
};

, - Swap() .




[GoF]
., ., ., . - . .: . . — .: , 2001.
[Dewhurst]
, . C++. .: . . — .: , 2012.
[Meyers1]
, . C++. 55 .: . . — .: , 2014.
[Meyers2]
, . C++: 42 C++11 C ++14.: . . — .: «.. », 2016.
[Sutter1]
, . C++.: . . — : «.. », 2015.
[Sutter2]
Sutter, escudo de armas. Nuevas tareas complejas en C ++.: Per. De inglés - M: LLC "I.D. Williams, 2015.



Source: https://habr.com/ru/post/undefined/


All Articles