Überladungen

Content

C++ unterstützt das Überladen (overloading) von Namen. Das betrifft insbesondere Deklarationen von Funktionen, Methoden und Templates. Überladungen sind nur zulässig, wenn eine Unterscheidung aufgrund der Parameter bzw. Template-Parameter möglich ist.

Folgende Überladung ist beispielsweise unzulässig, weil sich die beiden Funktionsdeklarationen nur beim Return-Typ unterscheiden und somit eine Differenzierung aufgrund der Parameter nicht möglich ist:

int mid(int a, int b) {
   return (a + b) / 2;
}

double mid(int a, int b) {
   return (a + b) / 2.0;
}
theon$ g++ -Wall -c bad-overloading.cpp
bad-overloading.cpp: In function 'double mid(int, int)':
bad-overloading.cpp:5:8: error: ambiguating new declaration of 'double mid(int, int)'
 double mid(int a, int b) {
        ^~~
bad-overloading.cpp:1:5: note: old declaration 'int mid(int, int)'
 int mid(int a, int b) {
     ^~~
theon$ 

Solange die Unterscheidbarkeit gegeben ist, dürfen beliebig viele Deklarationen den gleichen Namen verwenden.

Wenn dann der Name genutzt wird, findet eine Auswahl in zwei Phasen statt:

Wenn bei der ersten Phase kein Kandidat übrigbleibt, ist es ein Fehler. Neuere Übersetzer liefern dann typischerweise eine Liste der namentlich passenden Deklarationen, wobei sie dann jeweils begründen, warum sie nicht passen. Das führt oft zu längeren Fehlermeldungen:

#include <cstdlib>

int foo(int) {
   return 0;
}

template<typename T>
int foo(const T*) {
   return 1;
}

template<typename T, std::size_t N>
int foo(const T (&a)[N]) {
   return N;
}

int main() {
   int i = foo(main);
}
theon$ g++ -Wall -c no-candidates.cpp
no-candidates.cpp: In function 'int main()':
no-candidates.cpp:18:20: error: no matching function for call to 'foo(int (&)())'
    int i = foo(main);
                    ^
no-candidates.cpp:3:5: note: candidate: int foo(int) 
 int foo(int) {
     ^~~
no-candidates.cpp:3:5: note:   conversion of argument 1 would be ill-formed:
no-candidates.cpp:18:20: error: invalid conversion from 'int (*)()' to 'int' [-fpermissive]
    int i = foo(main);
                    ^
no-candidates.cpp:8:5: note: candidate: template int foo(const T*)
 int foo(const T*) {
     ^~~
no-candidates.cpp:8:5: note:   template argument deduction/substitution failed:
no-candidates.cpp:18:20: note:   types 'const T' and 'int()' have incompatible cv-qualifiers
    int i = foo(main);
                    ^
no-candidates.cpp:13:5: note: candidate: template int foo(const T (&)[N])
 int foo(const T (&a)[N]) {
     ^~~
no-candidates.cpp:13:5: note:   template argument deduction/substitution failed:
no-candidates.cpp:18:20: note:   mismatched types 'const T [N]' and 'int()'
    int i = foo(main);
                    ^
no-candidates.cpp:18:8: warning: unused variable 'i' [-Wunused-variable]
    int i = foo(main);
        ^
theon$ 

Die bei der zweiten Phase zur Anwendung kommende Ordnung ist nur partiell, d.h. diese Phase kann damit enden, dass wir am Ende mehrere gleichrangig gute Kandidaten haben. Das wird als Fehler behandelt:

#include <cstdlib>

int foo(int) {
   return 0;
}

template<typename T>
int foo(const T*) {
   return 1;
}

template<typename T, std::size_t N>
int foo(const T (&a)[N]) {
   return N;
}

int main() {
   int i = foo("hi");
}
theon$ g++ -Wall -c ambiguous.cpp
ambiguous.cpp: In function 'int main()':
ambiguous.cpp:18:20: error: call of overloaded 'foo(const char [3])' is ambiguous
    int i = foo("hi");
                    ^
ambiguous.cpp:8:5: note: candidate: int foo(const T*) [with T = char]
 int foo(const T*) {
     ^~~
ambiguous.cpp:13:5: note: candidate: int foo(const T (&)[N]) [with T = char; long unsigned int N = 3]
 int foo(const T (&a)[N]) {
     ^~~
ambiguous.cpp:18:8: warning: unused variable 'i' [-Wunused-variable]
    int i = foo("hi");
        ^
theon$ 

Die hier verwendete Zeichenkette "hi" ist vom Datentyp const char [3] (zwei Zeichen plus Nullbyte), die wegen der Dualität von Zeigern und Arrays aber auch ohne Konvertierung als const char* interpretiert werden kann.

Aufgabe

Schreiben Sie eine Funktion dim, die die Dimensionierung verschiedener Argumente liefert. Zu unterstützen sind

Folgendes Testprogramm sollte damit funktionieren:

#include <iostream>
#include <vector>
#include "dim.hpp"

int main(int argc, char** argv) {
   std::cout << "argv: " << dim(argv) << std::endl;
   std::vector<int> a = {1, 2, 3, 4};
   std::cout << "a: " << dim(a) << std::endl;
   int b[] = {5, 6, 7};
   std::cout << "b: " << dim(b) << std::endl;
}
theon$ g++ -Wall -o testit testit.cpp
theon$ ./testit 1 2 3 4 5 6
argv: 7
a: 4
b: 3
theon$ 

Zu beachten sind folgende Punkte: