2016-11-13 3 views
0

Ich spielte mit C++ 17/C++ 1z Funktionen apply und invoke ein bisschen Letztlich wollte ich apply das Ergebnis der equal_range direkt wie folgt verwenden:Wie std :: distance a Callable für anwenden oder aufrufen?

cout << apply(std::distance, data.equal_range(4)) << '\n'; 

, das nicht kompilieren. Ich dachte, es war, weil equal_range eine pair und nicht eine tuple zurückgegeben, aber wie sich herausstellt, ist das nicht der Fall.

Mein größeres Beispiel kompiliert alles, wenn ich ein Lambda anstelle vonverwende. Wenn ich über den Grund dafür nachdenke, nehme ich an, dass es etwas damit zu tun hat, die Template-Funktion distance zu instantiieren. Hrm, schadet, dass dies nicht ohne es funktioniert, weil ich eine harte Zeit, es mit `std :: Abstand :: iterator>

#include <iostream> 
#include <set> 
#include <functional> // invoke 
#include <experimental/tuple> // apply 

using std::set; using std::cout; 
using std::invoke; 
using std::experimental::apply; 

int main() { 
    set<int> data { 1,2,3,4,5,6 }; 

    // the C++11-way, not possible in one line. 
    auto r = data.equal_range(4); 
    cout << std::distance(r.first, r.second) << '\n'; 

#if 0 // do not work 
    cout << invoke(std::distance, r.first, r.second) << '\n'; 
    cout << apply(std::distance, r) << '\n'; 
    cout << apply(std::distance, make_tuple(r.first, r.second)) << '\n'; 
    cout << apply(std::distance, data.equal_range(4)) << '\n'; 
#endif 

// explicitly instantiate distance: intolerably cumbersome 
cout << apply(std::distance<set<int>::iterator>, data.equal_range(4)) << '\n'; 

    // using a lambda: too long for a single line 
    auto d = [](auto b, auto e) { return std::distance(b, e); }; 
    cout << invoke(d, r.first, r.second) << '\n'; 
    cout << apply(d, r) << '\n'; 
    cout << apply(d, make_tuple(r.first, r.second)) << '\n'; 
    cout << apply(d, data.equal_range(4)) << '\n'; 
} 

Gibt es eine schöne, kompakte Weise apply zu verwenden Instanziieren haben würde und invoke mit Template-Funktionen wie distance ohne explizite Instanziierung oder Lambda?

+0

"Abstand" ist eine Funktionsvorlage, keine Vorlagenfunktion, das ist das Problem. ('Abstand :: Iterator>' wäre ein Beispiel für eine Template-Funktion.) – ildjarn

+0

@ildjarn Ich sehe, was Sie meinen, ich muss meine Terminologie gerade zu bekommen. Ok, ich weiß was eine * Funktionsvorlage * ist, aber was ist eine * Template Funktion * dann, wenn nicht nur eine * Funktion *? 'std :: distance' ist ein FT, warum ist 'distance :: iterator>' ein TF und nicht nur ein F? Weil es von einer FT instanziiert wird? Wenn ja, gibt es einen Unterschied zwischen einem TF und einem F? – towi

+2

"* was ist eine Template-Funktion dann, wenn nicht nur eine Funktion *" Es ist in der Tat nur eine Funktion, aber es ist niedriger in Überladung Auflösung als eine "normale" Funktion und ist es daher wert zu unterscheiden. (In diesem Fall gibt es keinen Überladungssatz, der sowohl aus Funktionen als auch aus Vorlagenfunktionen besteht, also trifft dies hier nicht zu.) – ildjarn

Antwort

1
#define OVERLOADS_OF(...)\ 
    [](auto&&...args)->decltype(auto){\ 
    return __VA_ARGS__(decltype(args)(args)...);\ 
    } 

jetzt OVERLOADS_OF(std::distance) ist ein Lambda, die std::apply geben werden kann.

Ich habe mindestens einen Vorschlag gesehen, um dies (in schöner Syntax, und nicht Makro-basiert) in den Standard zu bringen; Ich kenne seinen Status nicht.

+0

in der Tat sehr nett. Nur zwei Nachteile: a) verwendet eine Gnu-Erweiterung, b) verwendet ein Makro. Aber trotzdem gut bemerkt. – towi

+0

@towi was gcc-Erweiterung? '__VA_ARGS__' ist C99. – Yakk

+0

Ok, dann hat meine Google-Suche nach mir falsche Infos gezeigt. Wahrscheinlich habe ich [diese Antwort] falsch interpretiert (https://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick). – towi

Verwandte Themen