Overloading in C ++. Part I. Overloading functions and templates


C ++ is a complex and interesting language, you can improve in it almost all your life. At some point, I wanted to study it as follows: take some aspect of the language, possibly quite narrow, and deal with it as deeply and in detail as possible. This approach was largely stimulated by the remarkable books of Scott Meyers, Herb Sutter, and Stephen Dewhurst. When a certain amount of materials had accumulated, I decided to introduce Khabrovchan to them. So there was this series, which I called "C ++, digging in depth." The series is marked as Tutorial, but it is still focused not on beginners, but rather on the intermediate level. The first topic is overloading in C ++. The topic turned out to be very extensive and we got three articles. The first article is about overloading functions and templates, the second is overloading operators and the third is overloading operatorsnew/delete. So, let's start digging.



Table of contents


Table of contents

  
  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
     .
  




Introduction


In a broad sense, overloading is the ability to simultaneously use several functions with the same name. The compiler distinguishes them due to the fact that they have a different set of parameters. At call points, the compiler analyzes the types of arguments and determines which particular function should be called. In Russian-language literature, the term β€œsharing” can sometimes be found, but it does not seem to have taken root.


Overloading is supported by many programming languages, we will consider only C ++ 17.



1. General Provisions



1.1. Overloaded Functions


( ) (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, Coat of Arms. New complex tasks in C ++ .: Per. from English - M: LLC β€œI.D. Williams, 2015.



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


All Articles