2013-01-18 15 views
5

Wewnątrz algorytmu, chcę stworzyć lambda, która akceptuje elementu poprzez odniesienie do const:Przechodząc element z lambda przez reference-to-const

template<typename Iterator> 
void solve_world_hunger(Iterator it) 
{ 
    auto lambda = [](const decltype(*it)& x){ 
     auto y = x; // this should work 
     x = x;  // this should fail 
    }; 
} 

Kompilator nie lubi ten kod :

Error: »const«-qualifier cannot be applied to »int&« (translated manually from German)

Wtedy zdałem sobie sprawę, że decltype(*it) jest już odniesienia, i oczywiście te, które nie mogą być wykonane const. Jeśli usuniemy const, kod się skompiluje, ale chcę, aby x = x się nie powiodło.

Pozwól nam zaufać programistce (która jest mną) przez minutę i pozbyć się const i jawnej, która zostaje usunięta ze względu na reguły zwijania odniesienia, tak czy inaczej. Ale czekaj, to decltype(*it) faktycznie gwarantowane być referencją, czy powinienem dodać wyraźne &, aby być po bezpiecznej stronie?

Jeśli nie ufamy programista, mogę pomyśleć dwa rozwiązania, aby rozwiązać problem:

(const typename std::remove_reference<decltype(*it)>::type& x) 

(const typename std::iterator_traits<Iterator>::value_type& x) 

Możesz sam zdecydować, który z nich jest brzydsze. Idealnie, chciałbym mieć rozwiązanie, które nie wymaga żadnego meta-programowania szablonów, ponieważ moja grupa docelowa nigdy wcześniej o tym nie słyszała. A więc:

Pytanie 1: Czy decltype(*it)& jest zawsze takie samo jak decltype(*it)?

Pytanie 2: Jak mogę przekazać element przez odniesienie do stałej bez meta-programowania szablonów?

+2

Błąd angielski byłby miły! :) – Pubby

+0

@Pubby Próbowałem, co w mojej mocy, nie krępuj się poprawić :) – fredoverflow

+0

@sehe pytanie nie jest o const na najwyższym poziomie. –

Odpowiedz

4

Pytanie 1: nie, wymaganie dotyczące InputIterator jest tylko tym, że *it można zamienić na T (tabela 72, w "Wymagania dotyczące iteratora").

Więc decltype(*it) mogłaby być na przykład const char& dla iteratora którego value_type jest int. Lub może to być int. Lub double.

Używanie iterator_traits nie jest równoznaczne z użyciem decltype, zdecyduj, który chcesz.

Z tego samego powodu auto value = *it; ma nie koniecznie podać zmienną z typem wartości iteratora.

Pytanie 2: może zależeć od tego, co rozumiemy przez metaprogramowanie szablonów.

Jeśli typem cech jest TMP, nie ma możliwości określenia "odwołania do typu wartości iteratora" bez TMP, ponieważ iterator_traits jest jedynym środkiem dostępu do typu wartości dowolnego iteratora.

Jeśli chcesz uzyskać decltype, to co z tym zrobić?

template<typename Iterator> 
void solve_world_hunger(Iterator it) 
{ 
    const auto ret_type = *it; 
    auto lambda = [](decltype(ret_type)& x){ 
     auto y = x; // this should work 
     x = x;  // this should fail 
    }; 
} 

Można mieć do przechwytywania ret_type aby używać jej typ, nie mogę łatwo sprawdzić w tej chwili.

Niestety dereferencje iteratora mają dodatkowy czas. Prawdopodobnie możesz napisać jakiś sprytny kod, aby tego uniknąć, ale sprytny kod stanie się alternatywną wersją remove_reference, stąd TMP.

+0

Dobra, ugryzę kulę i wyjaśnię "iterator_traits". – fredoverflow

+0

@FredOverflow: pisanie książki/samouczka? –

+0

Nie. Jeśli napisałem książkę, jestem pewien, że Lounge będzie pierwszą osobą, która się o tym dowie;) – fredoverflow

Powiązane problemy