Jste zde

Méně známé skutečnosti o C a C++: Implicitní parametr funkce nemusí být konstanta

C++ v rámci větší uživatelské přítulnosti poskytuje kromě přetěžování (overload) funkcí/metod také implicitní (default) hodnoty parametrů funkcí/metod (na rozdíl od Javy, u které mně tento syntaktický cukr celkem chybí). Většina programátorů v C++ o tom ví a tuto skutečnost využívá. Co už se ale ví méně, je to, že implicitního parametr funkce nemusí být konstanta. V tomto příspěvku se nebudu zabývat tím, do jaké míry je to vhodné a použitelné (ve většině případů to totiž opravdu vhodné není), ale pouze tím, co C++ v tomto směru umožňuje.

Standard C++98 říká (sekce 8.3.6 - Default arguments), že implicitním argumentem je výraz (expression). Pro úplnost dodávám, že na tento výraz jsou kladena určitá omezení (např. se nesmí jednat o lokální proměnnou, this atd., viz norma), ale ukázky v tomto příspěvku budou validní. Jdeme tedy na to.

Implicitní hodnotou parametru je hodnota statické proměnné

Na začátek něco jednoduchého.

#include <iostream>
 
using namespace std;
 
class A {
    public:
        static int defX;
 
        static void f(int x = defX) { cout << "f(): " << x << endl; }
};
int A::defX = 5;
 
int main() {
    A::f(); // Prints "f(): 5"
    A::defX = 13;
    A::f(); // Prints "f(): 13"
}

Podobný kód je velice běžný, ovšem s tou výjimkou, že defX bývá konstanta. Zde tomu ovšem tak není a jak vidíme, tak výstup volání metody A::f() se liší podle toho, jakou hodnotu má statická proměnná defX třídy A.

Implicitní hodnotou parametru je výsledek volání funkce

Nyní něco zajímavějšího.

#include <iostream>
#include <cstdlib>
 
using namespace std;
 
class B {
    public:
        static void f(int x = rand()) { cout << "f(): " << x << endl; }
};
 
int main() {
    B::f(); // Prints "f(): 1804289383"
    B::f(); // Prints "f(): 846930886"
}

Norma nám zaručuje, že výraz, který tvoří implicitní hodnotu parametru, bude vyhodnocen při každém volání funkce/metody (což bylo ostatně potřeba už v minulém příkladu). Nic nám tedy nebrání na místo implicitní hodnoty parametru dát volání funkce rand() (mimochodem, po absolvování kurzu funkcionálních jazyků se mně začíná příčit nazývat "funkci" rand() funkcí :), ale ve smyslu jazyka C++ to funkce je). Při každém zavolání metody f() třídy B tedy dojde k vypsání pseudonáhodného čísla.

Změna hodnoty implicitního parametru změnou deklarace funkce

A nakonec něco divočejšího.

#include <iostream>
 
using namespace std;
 
void f(int x = 2) { cout << "f(): " << x << endl; }
 
int main() {
    f();   // Prints "f(): 2"
    void f(int x = 7);
    f();   // Prints "f(): 7"
    ::f(); // Prints "f(): 2"
}

Po prvním zavolání funkce f() dojde k výpisu čísla 2, ale stačí na lokální úrovni změnit deklaraci funkce f() a při jejím následném zavolání dostaneme změněný výpis. Pokud bychom nyní chtěli zavolat funkci f() z deklarace na globální úrovni, lze použít operátor ::. Detaily viz norma C++98, sekce 8.3.6.4 a 5.1.4.

Přidat komentář