2013-01-18 6 views
5

Innerhalb eines Algorithmus Geben, möchte ich eine Lambda schaffen, die ein Element durch Verweis auf const akzeptiert:ein Element zu einem Lambda durch Verweis auf 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 
    }; 
} 

Der Compiler nicht mag diesen Code :

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

Dann erkannte ich, dass decltype(*it) bereits eine Referenz ist, und natürlich werden diejenigen nicht const gemacht. Wenn ich die const entferne, kompiliert der Code, aber ich möchte x = x fehlschlagen.

Lassen Sie uns dem Programmierer (der mich ist) für eine Minute vertrauen und die const und die explizite & loswerden, die sowieso aufgrund der kollabierenden Referenzregeln gelöscht wird. Aber warte, ist decltype(*it) eigentlich garantiert eine Referenz zu sein, oder sollte ich die explizite & auf der sicheren Seite hinzufügen?

Wenn wir den Programmierer nicht vertrauen, kann ich glaube, zwei Lösungen das Problem zu lösen:

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

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

Sie können selbst entscheiden, welche hässlicher ist. Im Idealfall möchte ich eine Lösung, die keine Template-Metaprogrammierung beinhaltet, weil meine Zielgruppe noch nie davon gehört hat. Also:

Frage 1: Ist decltype(*it)& immer das gleiche wie decltype(*it)?

Frage 2: Wie kann ich ein Element durch Referenz-zu-Const ohne Vorlage Meta-Programmierung übergeben?

+2

Ein englischer Fehler wäre nett! :) – Pubby

+0

@Pubby Ich versuchte mein Bestes, fühle mich frei zu korrigieren :) – fredoverflow

+0

@sehe die Frage ist nicht über Top-Level const. –

Antwort

4

Frage 1: Nein, die Anforderung an InputIterator ist lediglich, dass *it in T konvertierbar ist (Tabelle 72, in "Iterator-Anforderungen").

decltype(*it) könnte also zum Beispiel const char& für einen Iterator sein, deren value_type ist int. Oder es könnte int sein. Oder double.

Verwenden Sie iterator_traits ist nicht gleichbedeutend mit decltype, entscheiden, was Sie wollen.

Aus dem gleichen Grund, auto value = *it; tut nicht unbedingt geben Sie eine Variable mit dem Werttyp des Iterators.

Frage 2: könnte davon abhängen, was Sie mit Template-Metaprogrammierung meinen.

Wenn ein Merkmalstyp TMP ist, gibt es keine Möglichkeit, "const Referenz auf den Werttyp eines Iterators" ohne TMP anzugeben, da iterator_traits die einzige Möglichkeit ist, auf den Werttyp eines beliebigen Iterators zuzugreifen.

Wenn Sie die decltype const-ify wollen, wie wäre es dann?

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 
    }; 
} 

Möglicherweise müssen ret_type erfassen, um seine Art zu verwenden, kann ich nicht einfach im Moment überprüfen.

Leider dereferenziert der Iterator eine zusätzliche Zeit. Sie könnten wahrscheinlich einen cleveren Code schreiben, um das zu vermeiden, aber der clevere Code würde am Ende eine alternative Version von remove_reference sein, also TMP.

+0

Okay, ich beiße in die Kugel und erkläre 'iterator_traits' dann. – fredoverflow

+0

@FredOverflow: ein Buch/Tutorial schreiben? –

+0

Nein. Wenn ich ein Buch geschrieben habe, bin ich mir sicher, dass die Lounge das Erste sein wird;) – fredoverflow

Verwandte Themen