SFINAE ( anglicky selhání substituce není chyba , „neúspěšná substituce není chyba“) je pravidlo jazyka C++ spojené se šablonami a přetížením funkcí . Je široce používán „pro jiné účely“ - pro reflexi během kompilace : v závislosti na vlastnostech typu probíhá kompilace tak či onak.
Pravidlo SFINAE říká: Pokud nelze vypočítat konečné typy/hodnoty parametrů šablony funkce, kompilátor nevyhodí chybu, ale hledá jiné vhodné přetížení. Chyba bude ve třech případech:
Pravidlo existovalo již v C++98 a bylo vynalezeno, aby program negeneroval chyby, pokud by někde v hlavičkových souborech byla šablona se stejným názvem, daleko od kontextu. Ale později se ukázalo, že je to vhodné pro reflexi během kompilace. Zkratku SFINAE vymyslel David Vandervoord, autor C++ Patterns (2002).
Do Boost byla přidána jednoduchá šablona, která funguje na pravidle SFINAE a umožňuje za určitých podmínek vytvořit instanci šablony. enable_if
Ve standardu C++11 bylo pravidlo SFINAE poněkud vylepšeno, aniž by se změnil koncept. Šablona tam také vstoupila (obecně , , a mnohem více bylo vypůjčeno z Boost ).enable_ifchronorandomfilesystem
V C++17 byl přidán konstrukt , který mírně snížil potřebu SFINAE. if constexpr()
C ++20 představilo . Jednak konstanta v závorkách je také součástí substituce, a pokud se nepodaří vypočítat, bude to neúspěšná substituce. Na druhou stranu to také snižuje potřebu SFINAE. Také se snížila potřeba konceptu SFINAE . explicit (true)
Předpokládejme, že potřebujeme zavolat funkci
f ( 1,2 ) ; _Existují verze této funkce:
( 1 ) void f ( int , std :: vektor < int > ); ( 2 ) void f ( int , int ); ( 3 ) void f ( double , double ); ( 4 ) void f ( int , int , char , std :: string , std :: vector < int > ); ( 5 ) void f ( std :: string ); ( 6 ) neplatné f (...);Kompilátor tyto funkce shromáždí do seznamu a podle určitých pravidel najde tu nejlepší – vytvoří rozlišení přetížení .
Krok 2, týkající se funkcí šablon, ještě nebyl aktivován. Přidejme do našeho seznamu další dvě funkce.
( 7 ) šablona < typename T > neplatný f ( T , T ); ( 8 ) šablona < typename T > void f ( T , název typu T :: iterátor );Funkce 7 bude ve čtvrtém kroku vyřazena, protože funkce bez šablony je vždy „silnější“ než šablonová.
Šablona 8 je daleko od našeho úkolu, protože je navržena pro určitou třídu, která má typ iterator. Druhým krokem je SFINAE : kompilátor říká, že T = int, pokusí se nahradit intv šabloně a ty šablony, u kterých náhrada nevedla k úspěchu, jsou zahozeny. Proto neúspěšné nahrazení není chybou .
Tento příklad se zkompiluje i v C++03 .
#include <iostream> #include <vektor> #include <set> šablona < typenameT > _ třídy DetectFind { struct Fallback { int find ; }; // přidat jméno člena "najít" struct Odvozeno : T , Fallback { }; šablona < název typu U , U > struct Kontrola ; typedef char Ano [ 1 ]; // typedef pro pole o velikosti jedna. typedef char č. [ 2 ]; // typedef pro pole o velikosti dvě. šablona < typename U > static No & func ( Check < int Fallback ::* , & U :: find > * ); šablona < typename U > statické Ano & func (...); veřejnost : typedef DetectFind typ ; enum { hodnota = sizeof ( func < Derived > ( 0 )) == sizeof ( Yes ) }; }; int main () { std :: cout << DetectFind < std :: vector < int >> :: hodnota << ' ' << DetectFind < std :: set < int > >:: hodnota << std :: endl ; návrat 0 ; }Jak to funguje: k řešení přetížení dochází v řetězci a konkrétní typ je silnější než proměnné argumenty . Vzhledem k tomu, že pod , není potřeba instanciovat šablonové funkce, stačí dosadit typy - funkce tedy mají pouze hlavičky bez těl. Druhá funkce, která vrací typ , bude vždy nahrazena, ale co ta první? sizeof(func<Derived>(0))Check<int Fallback::*, &U::find> *...funcsizeofYes
Bude nahrazen, pokud bude existovat typ šablony (protože pod ukazatelem není důležitý přesný typ, hlavní je existence). První parametr šablony je typ, druhý je konstanta tohoto typu. Ukazatel na -pole objektu se bere jako typ (ve skutečnosti posun od začátku objektu k poli), jako konstanta, ukazatel na pole . Konstanta bude definována a správného typu, pokud je jediné pole převzato z objektu – to znamená, že neexistuje žádné jiné vypůjčené z . CheckCheckintFallbackfindDerived::findFallbackfindT
C++ | |
---|---|
Zvláštnosti | |
Některé knihovny | |
Kompilátory | |
ovlivnil | |
|