webentwicklung-frage-antwort-db.com.de

C ++ 17: Behalten Sie nur einige Mitglieder bei, wenn Sie Tuple entpacken

Stellen wir uns vor, Sie müssen die folgende Methode aufrufen:

std::Tuple<int, int, int> foo();

In C++ 17 können Sie die Funktion aufrufen und das Tupel in einer einzigen Zeile entpacken:

auto [a, b, c] = foo();

Wie kann ich nun vorgehen, um nur b und c zu speichern und a zu verwerfen?

Derzeit sind mir nur zwei Optionen bekannt:


1 - Ich kann beim automatischen Entpacken eine Dummy-Variable verwenden

Die Dummy-Variable wird jedoch nicht verwendet und gibt eine Warnung aus. Wenn ich diese Warnung also stumm schalten möchte, ist der Code ziemlich unangenehm:

#pragma warning(Push)
#pragma warning(disable:4101)
// ReSharper disable once CppDeclaratorNeverUsed
auto [_, b, c] = foo();
#pragma warning(pop)

2 - Ich kann das gesamte Tupel speichern und mit std::get Den Verweis auf die einzigen Variablen abrufen, die ich benötige. Der Code ist weniger unangenehm, aber die Syntax ist auch weniger einfach.

Darüber hinaus erhöht sich die Größe dieses Codes für jeden neuen Wert, den wir im Tupel behalten möchten, um eine Zeile.

auto Tuple = foo();
int b = std::get<1>(Tuple);
int c = std::get<2>(Tuple);

Gibt es eine andere und einfachere Methode, um nur einige Parameter in ein Tupel zu entpacken?

63
Antoine C.

Eine andere Alternative ist die Verwendung eines std::tie:

int b, c;
std::tie(std::ignore, b, c) = foo();

Bearbeiten

Wie in den Kommentaren erwähnt, gibt es bei diesem Ansatz einige Probleme:

  • Keine Typinferenz möglich
  • Die Objekte müssen zuvor erstellt werden. Wenn die Standardkonstruktoren nicht trivial sind, ist dies keine gute Alternative.
42
Mansuro

Leider unterstützen strukturierte Bindungen das Verwerfen von Mitgliedern und Attributen wie [[maybe_unused]] kann nicht auf strukturierte Bindungen angewendet werden (es gibt einen Vorschlag dafür: P0609 : "Attribute für strukturierte Bindungen" ).

Hier ist eine mögliche Lösung:

auto [a, b, c] = foo();
(void) a; // unused
39
Vittorio Romeo

Sie könnten eine Hilfsfunktion schreiben, die nur bestimmte Indizes eines std::Tuple Zurückgibt:

template <size_t... Is, typename Tuple>
auto take_only(Tuple&& Tuple) {
    using T = std::remove_reference_t<Tuple>;

    return std::Tuple<std::Tuple_element_t<Is, T>...>(
        std::get<Is>(std::forward<Tuple>(Tuple))...);
}

auto [b, c] = take_only<1, 2>(foo());

Oder lässt den Kopf fallen oder so:

template <size_t... Is, typename Tuple>
auto drop_head_impl(Tuple&& Tuple, std::index_sequence<0, Is...> ) {
    return take_only<Is...>(std::forward<Tuple>(Tuple));
}

template <typename Tuple>
auto drop_head(Tuple&& Tuple) {
    return drop_head_impl(std::forward<Tuple>(Tuple),
        std::make_index_sequence<std::Tuple_size_v<std::decay_t<Tuple>>>());
}

auto [b, c] = drop_head(foo());

Die obigen Implementierungen weisen jedoch mit ziemlicher Sicherheit einige Probleme hinsichtlich der Komplexität der Lebensdauer auf, die bei der direkten Verwendung von strukturierten Bindungen nicht auftreten - da hier keine Verlängerung der Lebensdauer erfolgt.

Also tu einfach was Vittorio sagt :

auto [a, b, c] = foo();
(void)a;
21
Barry

MSVC hat bereits behoben dies in VS 15.7 Preview. Die endgültige Version 15.7 soll in den kommenden Wochen verfügbar sein. Dies bedeutet, dass die aktuelle Logik, die von den neuesten Versionen aller wichtigen Compiler unterstützt wird, wie folgt lautet:

  • Wenn mindestens eine der strukturierten Bindungen in einer strukturierten Bindungsdeklaration verwendet wird, wird für andere Bindungen in derselben Deklaration keine Warnung "Nicht verwendete Variable" ausgegeben.
  • Wenn keine der Bindungen in einer strukturierten Bindungsdeklaration verwendet wird, kann die Warnung mit dem [[maybe_unused]] Attribut:

    [[maybe_unused]] auto [a, b, c] = foo ();
5
Igor Akhmetov