2016-01-19 16 views
33
standardowy

C++ 14 określa następujące oświadczenie dla std::exchange:W std :: exchange, dlaczego drugi parametr szablonu jest domyślnie ustawiony?

template <class T, class U = T> 
T std::exchange(T& obj, U&& new_value); 

Zastanawiam się dlaczego U jest domyślnie T od U można znaleźć dzięki new_value. W jakim przypadku może to doprowadzić do innego wyniku niż:

template <class T, class U> 
T std::exchange(T& obj, U&& new_value); 

Odpowiedz

36

std::exchange została zaproponowana w N3511bez domyślnego szablonu argument, a następnie N3608 z domyślnym argumentem szablonu. Zauważ, że w N3608 następujące rozumowanie zostało dostarczone:

Nadanie Drugi szablon argumentu domyślną wartość ustala dwóch następujących przypadkach:

DefaultConstructible x = ...; 
if (exchange(x, {})) { ... } 

int (*fp)(int); 
int f(int); 
double f(double); 
/*...*/ exchange(fp, &f) /*...*/ 

Pierwszym przykładem jest przydatność jest oczywiście, że pozbawionym typu tymczasowy {} zostanie wydedukowany na T. Drugim przykładem jest bardziej zaangażowane:

14.8.2 Szablon odliczenie argumentu [temp.deduct]

5 Uzyskane podstawione i dostosować rodzaj funkcja jest stosowana jako rodzaj matrycy funkcyjnych matrycy odliczanie argumentów. Jeśli argument szablonu nie został wyprowadzony, a odpowiadający mu parametr szablonu ma domyślny argument, argument szablonu zostanie określony jako przez podstawienie argumentów szablonu określonych dla poprzednich parametrów szablonu na domyślny argument. Jeśli podstawienie powoduje niepoprawny typ, jak opisano powyżej, odliczenie nie powiedzie się.

14.8.2.5 Wydedukowania argumenty szablon z rodzaju [temp.deduct.type]

4 W większości przypadków, wartości typów, szablony, a nie typu, który jest stosowany do komponowania P uczestniczy w odrzucenie argumentu szablonu.To znaczy, mogą one być użyte do określenia wartości argumentu szablonu, a tak określona wartość musi być zgodna z wartościami określonymi w innym miejscu. Jednak w pewnych kontekstach wartość nie bierze udziału w odliczaniu typów, ale zamiast tego używa wartości argumentów szablonu, które zostały albo wyprowadzone gdzie indziej, albo wyraźnie określone. Jeśli parametr szablonu jest używany tylko w kontekstach nieprzebadanych i nie jest jednoznacznie określony , odliczanie argumentów szablonu nie powiedzie się.

5 niepoddanej wywnioskować konteksty są:

(5,5) - parametr funkcyjny, który odliczenie argument nie można tak dlatego, że związane funkcja argument jest funkcja lub zestaw przeciążonych funkcji (13,4), a jeden lub więcej z następujących zastosowanie:

(5.5.1) - więcej niż jedna funkcja dopasowuje parametr funkcja typ (w wyniku dwuznacznej odliczenia)

W drugim przykładzie parametr szablon U jest stosowany jedynie w ramach nie-wywnioskować, ponieważ obie przeciążenia f(int) i f(double) oba mogą być dopasowane do U. W związku z tym odliczanie argumentów nie ma miejsca, a U staje się domyślną wartością dostarczoną przez T (int (*)(int) w tym przypadku, więc wybrano f(int)).

Ponadto, jak wyjaśniono przez @VladfromMoscow, posiadanie domyślnego parametru pozwala na skrócenie kodu podczas przekazywania std::exchange<T> (do standardowego algorytmu np.).

+0

Gah! Mój umysł jest przepalony. Czy to jest nawet legalne? Wygląda na to, że 'f' jest zdefiniowane dwa razy. –

+1

@ JonathanMee Dwa przeciążenia dla 'f' są zadeklarowane. – TartanLlama

+6

@ JonathanMee, podstawowe funkcje przeciążania !? – StoryTeller

9

Funkcja może być przekazany jako argument do innej funkcji lub na przykład algorytmu. W tym przypadku wystarczy podać tylko pierwszy argument szablonu, jeśli oba argumenty funkcji będą miały ten sam typ.

Dzięki temu kod jest bardziej krótki i czytelny.

Oto przykład sztuczny. :)

#include <iostream> 
#include <numeric> 
#include <iterator> 
#include <functional> 


int main() 
{ 
    int a[] = { 1, 2, 3 }; 
    int b[] = { 4, 5, 6 }; 

    std::cout << "a: "; 
    for (int x : a) std::cout << x << ' '; 
    std::cout << std::endl; 
    std::cout << "b: "; 
    for (int x : b) std::cout << x << ' '; 
    std::cout << std::endl; 

    auto sum = std::inner_product(std::begin(a), std::end(a), 
            std::make_move_iterator(std::begin(b)), 0, 
            std::plus<int>(), std::exchange<int>); 

    std::cout << "sum = " << sum << std::endl; 
    std::cout << "a: "; 
    for (int x : a) std::cout << x << ' '; 
    std::cout << std::endl; 
} 

Wyjście jest

a: 1 2 3 
b: 4 5 6 
sum = 6 
a: 4 5 6 

Albo Przykładem może obejmować konwersję

#include <iostream> 
#include <numeric> 
#include <iterator> 
#include <functional> 


int main() 
{ 
    int a[] = { 1, 2, 3 }; 
    double b[] = { 4.4, 5.5, 6.6 }; 

    std::cout << "a: "; 
    for (int x : a) std::cout << x << ' '; 
    std::cout << std::endl; 
    std::cout << "b: "; 
    for (double x : b) std::cout << x << ' '; 
    std::cout << std::endl; 

    auto sum = std::inner_product(std::begin(a), std::end(a), 
            std::make_move_iterator(std::begin(b)), 0, 
            std::plus<>(), std::exchange<int>); 

    std::cout << "sum = " << sum << std::endl; 
    std::cout << "a: "; 
    for (int x : a) std::cout << x << ' '; 
    std::cout << std::endl; 
} 
+0

Czy możesz podać przykład kodu użycia? – Vincent

+1

@Vincent Zobacz mój zaktualizowany wpis. –

Powiązane problemy