Udostępnij za pośrednictwem


enable_if — Klasa

Warunkowo sprawia, że wystąpienie typu na SFINAE przeciążenia.Zagnieżdżone typedef enable_if<Condition,Type>::type istnieje — i jest synonimem Type— tylko wtedy, gdy Condition jest true.

template<bool B, class T = void>
    struct enable_if;

Parametry

  • B
    Wartość, która określa istnienia typu Wynikowe.

  • T
    Typ tworzenia wystąpienia, jeśli B jest true.

Uwagi

Jeśli B ma wartość true, enable_if<B, T> ma zagnieżdżonej typedef o nazwie "typ", który jest synonimem dla T.

Jeśli B ma wartość false, enable_if<B, T> nie ma zagnieżdżonej aliasów o nazwie "type".

Znajduje się szablon ten alias:

template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;

W języku C++ awarii podstawiania parametrów szablonu nie jest to błąd w sobie — jest to określane jako SFINAE (Brak podstawiania nie jest błąd).Zazwyczaj enable_if służy do usuwania kandydatów z wiązaniem — to znaczy, ubój zestaw przeciążenie — tak, że jedna definicja mogą zostać odrzucone na rzecz innego.Odpowiada to zachowanie SFINAE.Aby uzyskać więcej informacji o SFINAE, zobacz awarii podstawiania to nie jest błąd Wikipedii.

Oto cztery przykładowe scenariusze:

  • Scenariusz 1: Zawijanie zwracany typ funkcji:

    template <your_stuff> typename enable_if<your_condition, your_return_type>::type
    yourfunction(args) {
        // ...
    }
    
    // The alias template makes it more concise:
    template <your_stuff>
    enable_if_t<your_condition, your_return_type> yourfunction(args) {
        // ...
    }
    
  • Scenariusz 2: Dodawanie parametru funkcji, która ma argument domyślny:

    template <your_stuff> your_return_type_if_present
    yourfunction(args, enable_if_t<your condition, FOO> = BAR) {
        // ...
    }
    
  • Scenariusz 3: Dodanie parametru szablonu, który ma argument domyślny:

    template <your_stuff, typename Dummy = enable_if_t<your_condition>>
    rest_of_function_declaration_goes_here
    
  • Scenariusz 4: Jeśli funkcja ma argument bez szablonu, można zawijać jej typ:

    template <typename T>
    void your_function(const T& t,
        enable_if_t<is_something<T>::value, const string&> s) {
        // ...
    }
    

Scenariusz 1 nie działa z konstruktorów i operatory konwersji, ponieważ nie mają zwracanych typów.

Scenariusz 2 pozostawia nienazwany parametr.Można powiedzieć, ::type Dummy = BAR, ale nazwa Dummy nie ma znaczenia, i nadając mu nazwę prawdopodobnie ostrzeżenie "nieużywane parametr".Musisz wybrać FOO typ parametru funkcji i BAR argument domyślny.Można powiedzieć, int i 0, ale następnie użytkowników o kodzie może przypadkowo przejść do funkcji dodatkowych liczbę całkowitą, która może być ignorowane.Zamiast tego zaleca się używanie void ** i 0 lub nullptr ponieważ prawie nic nie jest konwertowany na void **:

template <your_stuff> your_return_type_if_present 
yourfunction(args, typename enable_if<your_condition, void **>::type = nullptr) {
    // ...
}

Scenariusz 2 działa również w przypadku zwykłych konstruktorów.Jednak to nie działa dla operatory konwersji, ponieważ nie mogą one podjąć dodatkowe parametry.To także nie działa dla zmienne konstruktorów ponieważ dodanie dodatkowych parametrów sprawia, że parametr funkcji pack kontekstu nie wynikają, a tym samym pokonuje celem enable_if.

Scenariusz 3 będzie miał nazwę Dummy, ale jest opcjonalny.Po prostu "typename = typename" będzie działać, ale jeśli uważasz, że wygląda dziwnie, można użyć nazwy "ślepe" — po prostu nie używać taki, który może być także używany w definicji funkcji.Jeśli nie podajesz typu do enable_if, to domyślnie do unieważnienia i doskonale to uzasadnione, ponieważ nie obchodzi co Dummy jest.To działa dobrze dla wszystkiego, w tym operatory konwersji i zmienne konstruktorów.

Scenariusz 4 działa w konstruktorów, które nie mają zwracanych typów, a tym samym rozwiązuje ograniczenia zawijania scenariusz 1.Scenariusz 4 jest jednak ograniczone do argumentów funkcji bez szablonu, które nie zawsze są dostępne.(Używanie Scenariusz 4 w argumencie funkcji opartych na szablonach uniemożliwia potrącenia argumentu szablon z pracy nad nim).

enable_ifjest potężnym, ale także niebezpieczne, jeśli jest używane.Ponieważ jej celem jest zapewnienie kandydatów zniknąć przed wiązaniem, gdy jest wykorzystywane, jego skutki mogą być bardzo mylące.Poniżej przedstawiono kilka zaleceń:

  • Nie należy używać enable_if aby wybrać między implementacjami w czasie kompilacji.Nigdy nie pisz jeden enable_if dla CONDITION , a drugi do !CONDITION.Zamiast tego należy użyć wysyłki ze znacznikiem wzór — na przykład z algorytmu, który wybiera implementacji w zależności od mocnych Iteratory są one podane.

  • Nie należy używać enable_if do wymuszania wymagań.Jeśli chcesz sprawdzić poprawność parametrów szablonu i sprawdzanie poprawności nie powiedzie się, powodują wystąpienie błędu nie wybiera inną implementacją, użyj static_assert.

  • Użycie enable_if kiedy masz zestawu przeciążenie, sprawia, że w przeciwnym razie dobry kod niejednoznaczne.Najczęściej dzieje się w sposób niejawny konwersji konstruktorów.

Przykład

W tym przykładzie wyjaśnia jak funkcja szablon STL std::make_pair() korzysta z enable_if.

void func(const pair<int, int>&);
void func(const pair<string, string>&);

func(make_pair("foo", "bar"));

W tym przykładzie make_pair("foo", "bar") zwraca pair<const char *, const char *>.Ma przeciążeń z późnym wiązaniem do określenia, które func() chcesz.pair<A, B>ma niejawnie konwersji Konstruktor z pair<X, Y>.Nie jest to nowy — to było w C ++ 98.Jednak w C ++ 98/03, podpis konstruktora niejawnej konwersji zawsze istnieje, nawet jeśli jest pair<int, int>(const pair<const char *, const char *>&).Przeciążeń z późnym wiązaniem nie obchodzi, że próba uruchomienia tego konstruktora wybucha Strasznie bo const char * nie jest jawnie konwertowany na int; to tylko patrzenie podpisy przed funkcji, której wystąpienia są tworzone definicje.W związku z tym, przykładowy kod jest niejednoznaczny, ponieważ istnieją podpisów do konwersji pair<const char *, const char *> zarówno pair<int, int> i pair<string, string>.

C++11 solved this ambiguity by using enable_if to make sure pair<A, B>(const pair<X, Y>&) exists only when const X& is implicitly convertible to A and const Y& is implicitly convertible to B.Dzięki temu przeciążeń z późnym wiązaniem ustalenie, że pair<const char *, const char *> nie jest konwertowany na pair<int, int> i że przeciążenie zabiera pair<string, string> jest w dobrej kondycji.

Wymagania

Nagłówek: < type_traits >

Przestrzeń nazw: std

Zobacz też

Informacje

<type_traits>

Inne zasoby

<type_traits> Członkowie