2016-03-28 18 views
4

In this answer Ich schrieb den C++ 17-Code decltype:Gibt es eine Verknüpfung

cout << accumulate(cbegin(numbers), cend(numbers), decay_t<decltype(numbers[0])>{}); 

Dieser einige negative Kommentare über die Natur der C++ 's Typzuordnung erhalten, die ich traurig zu sagen bin, dass ich zustimmen mit :(

decay_t<decltype(numbers[0])>{} ist eine sehr komplexe Art und Weise ein zu bekommen:

Zero-initialized type of an element of numbers

ist es möglich beizubehalten, um die Verbindung mit der Art der numbers ' Elemente, aber nicht wie 30 Zeichen, um es zu bekommen?

EDIT:

Ich habe eine Menge Antworten bekam die einen Wrapper für entweder accumulate oder zum Extrahieren des Typs von numbers[0] beteiligt sind. Das Problem besteht darin, dass der Leser zu einem sekundären Standort navigieren muss, um eine Lösung zu lesen, die nicht weniger komplex ist als der Initialisierungscode decay_t<decltype(numbers[0])>{}.

Der einzige Grund, dass wir mehr als dies zu tun: decltype(numbers[0]) ist, weil die array subscript operator einen Verweis zurückgibt:

error: invalid cast of an rvalue expression of type 'int' to type 'int&'

Es ist interessant, dass in Bezug auf decltype ‚Argument:

If the name of an object is parenthesized, it is treated as an ordinary lvalue expression

Jedoch ist decltype((numbers[0])) immer noch nur ein Verweis auf ein Element von numbers. Also am Ende diese Antworten können so nah wie wir zur Vereinfachung diese Initialisierung kommen kann :(

+0

verwenden würden, wenn Sie eine Null wollen, schreiben Sie es einfach so nach unten: 0. Es gibt keine ist müssen Pilion auf Ossa stapeln. –

+0

@ n.m. Das ist absolut falsch, mein Herr. Eine '0' wird 'accumulate'' init' als 'int' definieren. Wenn wir zum Beispiel mit 'float numbers []' arbeiten, werden die Werte abgeschnitten. [Dieses Beispiel] (http://ideone.com/A12xin) sollte beispielsweise 11.2 ausgeben, aber wenn ich eine "0" verwende, wird 10 ausgegeben. –

+0

Ja, Sie haben Recht. Ich habe std vergessen: accumulate is broken ... –

Antwort

1

Ich denke, das Beste, was Sie tun können, ist gerade dies irgendwo ausklammern:

template <class It, class R = std::decay_t<decltype(*std::declval<It>())>> 
R accumulate(It first, It last, R init = 0) { 
    return std::accumulate(first, last, init); 
} 

std::cout << accumulate(cbegin(numbers), cend(numbers)); 

Oder allgemeiner:

template <class Range, class T = 
     std::decay_t<decltype(*adl_begin(std::declval<Range&&>()))>> 
T accumulate(Range&& range, T init = 0) { 
    return std::accumulate(adl_begin(range), adl_end(range), init); 
} 

cout << accumulate(numbers); 

wo adl_begin ist eine Version von begin(), die für die ADL-Konten.

sicher, wir haben technisch noch alle t er cruft, dass du früher vermeiden wolltest ... aber jetzt musst du es nie wieder anschauen?

+0

Ummm ... Was ist ADL? –

+0

@ JonathanMee Argument-abhängig lookup – Barry

+0

Kannst du mir helfen zu verstehen, was 'begin' und' end' mit [ADL] (http://en.cppreference.com/w/cpp/language/adl) zu tun haben? Ist das nur ein Versuch, herumzukommen? die C++ 14-Anforderung? –

2

Während ich immer eine Hilfsfunktion als pro @Barry, wenn Zahlen ein Standard-Container schreiben wählen würde, wird es die Art value_type exportieren, so dass Sie ein wenig Aufwand sparen können:

cout << accumulate(cbegin(numbers), cend(numbers), decltype(numbers)::value_type()); 

gehen weiter, könnten wir diese Template-Funktion definieren:

template<class Container, class ElementType = typename Container::value_type> 
constexpr auto element_of(const Container&, ElementType v = 0) 
{ 
    return v; 
} 

, die uns diese gibt:

cout << accumulate(cbegin(numbers), cend(numbers), element_of(numbers, 0)); 
2

Persönliche Präferenz: Ich finde die decay_t, decltype und declval tanzen ziemlich nervig und schwer zu lesen.

Stattdessen habe ich eine zusätzliche Dereferenzierungsebene durch eine Art-Merkmal value_t<It> und Null-Initialisierung durch init = R{}

template<class It> 
using value_t = typename std::iterator_traits<It>::value_type; 

template<class It, class R = value_t<It>> 
auto accumulate(It first, It last, R init = R{}) { /* as before */ } 
Verwandte Themen