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

Od Petr Zemek, 2009-07-13

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.

Obsah tohoto pole je soukromý a nebude veřejně zobrazen.

Filtrované HTML (využíváno)

  • Povolené HTML značky: <a href hreflang> <em> <strong> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <table>
  • Zvýraznění syntaxe kódu lze povolit přes následující značky: <code>, <blockcode>, <bash>, <c>, <cpp>, <haskell>, <html>, <java>, <javascript>, <latex>, <perl>, <php>, <python>, <ruby>, <rust>, <sql>, <text>, <vim>, <xml>, <yaml>.
  • Řádky a odstavce se zalomí automaticky.
  • Webové a e-mailové adresy jsou automaticky převedeny na odkazy.
CAPTCHA
3 + 3 =
Vyřešte tento jednoduchý matematický příklad a vložte výsledek. Např. pro 1+3 vložte 4.
Nějak se mi tady rozmohl spam, takže poprosím o ověření.