2013-07-19 13 views
23

Program Visual Studio 2013 Preview obsługuje funkcję C++ 14 o nazwie (zgodnie z this strona) "Przezroczyste funkcje operatora". Nie wiem, co to oznacza. Najbliższa propozycja C++ 14, którą znalazłem, jest taka, ale nie jestem pewna, czy to to samo: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421Przejrzyste operatory operatorów

Szukam bardziej jasnego wyjaśnienia, co to jest, dlaczego jest to poprawa, i może urywek demonstrujący jego użycie.

+0

Jeśli to jest to samo, pozwala zastąpić 'bool less :: operator() (int const & lhs, int const & rhs) const {return lhs :: operator() (LHS && lhs, RHS && rhs) const-> decltype (std :: forward (lhs) (rhs)) {return std :: forward (lhs) (rhs); } ', idealne przekazywanie" przezroczystego "wywołania' <'. – Yakk

+4

N3421 to to samo - zostało ono poddane pod głosowanie w C++ 14 bez modyfikacji na tym spotkaniu, a to zaimplementowałem w 2013 Preview. Pomyślałem, że sekcja II, "Motywacja i zakres", jasno wyjaśniła problem i rozwiązanie, i pomyślałem, że przykład w sekcji VIII "Wdrożenie" wykazał jego zastosowanie. Co cię myli? –

+0

Strona "Co nowego w Visual C++" nie zawiera propozycji N3421, więc pomyślałem, że o to tutaj zapytam. Teraz jestem jasny. Dziękujemy za dodanie. – GravityWell

Odpowiedz

22

Propozycja przezroczystych operatorów jest dostępna jako sposób na uogólnione funktory, które znajdują się w <functional>. Osobiście uważam, że sama propozycja ma bardzo dobry przykład, który pomógłby zilustrować jej potrzebę. Niemniej jednak postaram się to wyjaśnić.

Załóżmy, że masz funkcję, bardzo prosty umysł funkcyjny Ciebie:

template<typename T, typename U> 
auto less_than(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)) { 
    return std::forward<T>(t) < std::forward<U>(u); 
} 

jednak chcesz skorzystać z tej uogólnione funkcji w nagłówku <algorithm>. Masz dwie możliwości, aby to funktor struct:

struct MyLessThanFunctor { 
    template<typename T, typename U> 
    auto operator()(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)){ 
     return std::forward<T>(t) < std::forward<U>(u); 
    } 
}; 

Albo w C++ 14, aby polimorficzny lambda:

[](auto&& t, auto&& u) -> decltype(auto) { 
    return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u); 
} 

Oba są bardzo gadatliwe, gdy wykorzystywane w algorytmie tak jak :

int main() { 
    std::vector<int> v = {112,12,1281271,1919101,29181,412,1 }; 
    std::sort(std::begin(v), std::end(v), MyLessThanFunctor()); // one 
    std::sort(std::begin(v), std::end(v), [](auto&& t, auto&& u) -> decltype(auto) { 
     return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u); 
    }); 
} 

propozycja ta ma na celu uczynienie go bardziej zwarty i uogólnione w ten sposób zamiast:

std::sort(std::begin(v), std::end(v), std::less<>()); 

Zapewnia to doskonałe przekazywanie i rozwiązuje problemy związane ze skróceniem lub problemami wynikającymi ze zmiany kontenera, ale nie z podstawowym typem wyznaczonym przez kontener, jak wspomniano w dokumencie.

Załóżmy, że masz non-uogólnioną funktor:

struct Functor { 
    bool operator()(uint32_t a, uint32_t b) { 
     return a < b; 
    } 
}; 

i używasz go z std::vector<uint32_t> i działa wszystko w porządku, ale można zapomnieć o swojej funktora nie są uogólnione i używać go z std::vector<uint64_t>. Czy widzisz problem, który się pojawił? Elementy zostaną obcięte przed porównaniem, co prawdopodobnie nie jest tym, czego chciał użytkownik. Uogólnione funktory rozwiązują ten problem, zanim się pojawią.

+2

Możesz użyć 'std :: less' et al. nawet bez tych przezroczystych funktorów, które są implementowane, ale jest o wiele bardziej niewiarygodne.'std :: sort (std :: begin (v), std :: end (v), std :: less :: type>());' – Praetorian

+9

Pretoriański, rozważ heterogeniczny niższy poziom C++ 11(), gdzie zakres i pożądana wartość mogą mieć różne typy. C++ 98's mniej pobiera (const T &, const T &), więc bez względu na to, jaki wybierzesz T, nie możesz przeprowadzić heterogenicznego porównania. Ma to znaczenie nawet w przypadku prostych przypadków, takich jak std :: string i const char *. –

+0

Równoważna wartość lambda to '[] (auto && t, auto && u) -> decltype (auto) {return std :: forward (t) (u); } ', niestety –