Sdílet prostřednictvím


Tři tečky a variadické šablony

Tento článek uvádí, jak použít tři tečky (...) s šablonami variadic jazyka C++.Tři tečky měly mnoho využití v jazyce C a C++.Patří sem variabilní seznamy proměnných pro funkce.Funkce printf() z běhové knihovny jazyka C je jedním z nejlépe známých příkladů.

Variadická šablona je šablona třídy nebo funkce, která podporuje libovolný počet argumentů.Tento mechanismus je užitečné zejména pro vývojáře knihovny C++, protože ji můžete použít u šablon třídy i šablon funkcí a tím poskytnout širokou škálu netriviálních funkcí a flexibility.

Syntax

Trojtečka se ve variadických šablonách používá dvěma způsoby.Vlevo od názvu parametru, označuje sadu parametrů a napravo od názvu parametru rozšiřuje sady parametrů na oddělené názvy.

Zde je příklad základní variadické šablony třídy syntaxe definice:

template<typename... Arguments> class classname;

U sad parametrů a rozšíření můžete přidat mezery kolem elipsy, závislosti na vašich preferencích, jak je uvedeno v těchto příkladech:

template<typename ...Arguments> class classname;

Nebo toto:

template<typename ... Arguments> class classname;

Všimněte si, že tento článek používá konvence, která je zobrazena v prvním příkladu (se třemi tečkami se připojuje k typename).

V předchozích příkladech Arguments sada parametr.Třída classname může přijímat proměnný počet argumentů, jako v těchto příkladech:

template<typename... Arguments> class vtclass;

vtclass< > vtinstance1;
vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
vtclass<long, std::vector<int>, std::string> vtinstance4;

Pomocí definice tříd variadických šablon můžete také vyžadovat nejméně jeden parametr:

template <typename First, typename... Rest> class classname; 

Zde je příklad základní syntaxe variadické šablony funkce:

template <typename... Arguments> returntype functionname(Arguments... args);

Balíček parametrů Arguments je pak rozšířen pro potřeby použití, jak je znázorněno v následující části Principy variadických šablon.

Jsou možné také jiné formy syntaxe variadických funkcí šablon (včetně, ale nikoli výhradně, tyto příklady):

template <typename... Arguments> returntype functionname(Arguments&... args); 
template <typename... Arguments> returntype functionname(Arguments&&... args);
template <typename... Arguments> returntype functionname(Arguments*... args);

Specifikátory jako const jsou také povoleny:

template <typename... Arguments> returntype functionname(const Arguments&... args); 

Jako v případě definicí tříd variadických šablon, můžete vytvořit funkce, které vyžadují nejméně jeden parametr:

template <typename First, typename... Rest> returntype functionname(const First& first, const Rest&... args); 

Variadické šablony používají operátor sizeof...() (nesouvisející se starším operátorem sizeof()):

template<typename... Arguments>
void tfunc(const Arguments&... args)
{
    const unsigned numargs = sizeof...(Arguments);

    X xobj[numargs]; // array of some previously defined type X

    helper_func(xobj, args...);
}

Další informace o umístění elipsy

Dříve v tomto článku popsané umístění elipsy, který definuje sad parametrů a rozšíření jako "vlevo od názvu parametru, to znamená sadu parametrů a napravo od názvu parametru rozbalí sad parametrů do oddělené názvy".To je technicky pravdivé, ale může být matoucí v překladu kódu.Vezměte v úvahu:

  • V šabloně--seznam parametrů (template <parameter-list>), typename... představuje sadu parametrů šablon.

  • V parametru prohlášení klauzuli (func(parameter-list)), "nejvyšší" tři tečky představuje sadu parametrů funkce a umístění elipsy je důležité:

    // v1 is NOT a function parameter pack:
    template <typename... Types> void func1(std::vector<Types...> v1); 
    
    // v2 IS a function parameter pack:
    template <typename... Types> void func2(std::vector<Types>... v2); 
    
  • Pokud se třemi tečkami se zobrazí okamžitě po název parametru, máte rozšiřující pack parametr.

Příklad

Dobrým způsobem ke znázornění mechanismu funkce variadické šablony je jeho použití v přepsání některých funkcí printf:

#include <iostream>

using namespace std;

void print() {
    cout << endl;
}

template <typename T> void print(const T& t) {
    cout << t << endl;
}

template <typename First, typename... Rest> void print(const First& first, const Rest&... rest) {
    cout << first << ", ";
    print(rest...); // recursive call using pack expansion syntax
}

int main()
{
    print(); // calls first overload, outputting only a newline
    print(1); // calls second overload
    
    // these call the third overload, the variadic template, 
    // which uses recursion as needed.
    print(10, 20);
    print(100, 200, 300);
    print("first", 2, "third", 3.14159);
}

Výsledek

1
10, 20
100, 200, 300
first, 2, third, 3.14159

[!POZNÁMKA]

Většina implementací, které obsahují funkce šablony variadic, použití některou rekurzi, ale mírně se liší od tradičních rekurze.  Tradiční rekurze zahrnuje funkci volající sama sebe pomocí stejného podpisu. (Může být přetížené nebo bez vizuálního vzhledu, ale pokaždé je vybrána stejná signatura.) Variadická rekurze zahrnuje volání šablony variadické funkce pomocí odlišení (téměř vždy snížení) počtu argumentů a tím orazítkování jiného podpisu při každém použití."Základní případ" je stále zapotřebí, ale povaha rekurze se liší.

Viz také

Referenční dokumentace

Tři tečky (...)