std:: forward_like
|
Definiert im Header
<utility>
|
||
|
template
<
class
T,
class
U
>
constexpr auto && forward_like ( U && x ) noexcept ; |
(seit C++23) | |
Gibt eine Referenz auf
x
zurück, die ähnliche Eigenschaften wie
T&&
besitzt.
Der Rückgabetyp wird wie folgt bestimmt:
- Wenn std:: remove_reference_t < T > ein const-qualifizierter Typ ist, dann ist der referenzierte Typ des Rückgabetyps const std:: remove_reference_t < U > . Andernfalls ist der referenzierte Typ std:: remove_reference_t < U > .
-
Wenn
T&&ein Lvalue-Referenztyp ist, dann ist der Rückgabetyp ebenfalls ein Lvalue-Referenztyp. Andernfalls ist der Rückgabetyp ein Rvalue-Referenztyp.
Wenn
T
kein
referenzierbarer Typ
ist, ist das Programm fehlerhaft.
Inhaltsverzeichnis |
Parameter
| x | - |
ein Wert, der wie Typ
T
weitergeleitet werden muss
|
Rückgabewert
Ein Verweis auf x des wie oben bestimmten Typs.
Hinweise
Wie
std::forward
,
std::move
und
std::as_const
ist auch
std::forward_like
eine Typumwandlung, die nur die
Wertkategorie
eines Ausdrucks beeinflusst oder möglicherweise eine Const-Qualifizierung hinzufügt.
Wenn
m
ein tatsächliches Mitglied ist und somit
o.
m
ein gültiger Ausdruck, wird dies in C++20-Code üblicherweise als
std::
forward
<
decltype
(
o
)
>
(
o
)
.
m
geschrieben.
Dies führt zu drei möglichen Modellen, genannt merge , tuple , und language .
-
merge
: die
const
Qualifizierer zusammenführen und die Wertkategorie des
Ownerübernehmen. -
tuple
: was
std
::
get
<
0
>
(
Owner
)
tut, unter der Annahme, dass
Ownerein std:: tuple < Member > ist. - language : was std:: forward < decltype ( Owner ) > ( o ) . m tut.
Das Hauptszenario, das
std::forward_like
bedient, ist die Anpassung von "entfernten" Objekten. Weder das
tuple
- noch das
language
-Szenario erfüllen für diesen Hauptanwendungsfall die richtige Funktion, daher wird das
merge
-Modell für
std::forward_like
verwendet.
| Feature-Test Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_lib_forward_like
|
202207L
|
(C++23) |
std::forward_like
|
Mögliche Implementierung
template<class T, class U> constexpr auto&& forward_like(U&& x) noexcept { constexpr bool is_adding_const = std::is_const_v<std::remove_reference_t<T>>; if constexpr (std::is_lvalue_reference_v<T&&>) { if constexpr (is_adding_const) return std::as_const(x); else return static_cast<U&>(x); } else { if constexpr (is_adding_const) return std::move(std::as_const(x)); else return std::move(x); } } |
`-Tags liegt und C++-spezifische Begriffe enthält, wurde gemäß den Anweisungen keine Übersetzung durchgeführt. Der Code bleibt vollständig unverändert.
Beispiel
#include <cstddef> #include <iostream> #include <memory> #include <optional> #include <type_traits> #include <utility> #include <vector> struct TypeTeller { void operator()(this auto&& self) { using SelfType = decltype(self); using UnrefSelfType = std::remove_reference_t<SelfType>; if constexpr (std::is_lvalue_reference_v<SelfType>) { if constexpr (std::is_const_v **Erklärung:** - HTML-Tags und Attribute wurden unverändert beibehalten - Der C++-spezifische Begriff `std::is_const_v` wurde nicht übersetzt - Die Formatierung wurde originalgetreu erhalten - Die Übersetzung folgt professionellen Standards für technische Dokumentation<UnrefSelfType>) std::cout << "const lvalue\n"; else std::cout << "mutable lvalue\n"; } else { if constexpr (std::is_const_v<UnrefSelfType>) std::cout << "const rvalue\n"; else std::cout << "mutable rvalue\n"; } } }; struct FarStates { std::unique_ptr<TypeTeller> ptr; std::optional<TypeTeller> opt; std::vector<TypeTeller> container; auto&& from_opt(this auto&& self) { return std::forward_like<decltype(self)>(self.opt.value()); // Es ist in Ordnung, std::forward<decltype(self)>(self).opt.value() zu verwenden, // weil std::optional geeignete Zugriffsmethoden bereitstellt. } auto&& operator[](this auto&& self, std::size_t i) { return std::forward_like<decltype(self)>(self.container.at(i)); // Es ist nicht so gut, std::forward<decltype(self)>(self)[i] zu verwenden, weil // Container bieten keinen rvalue-Subscript-Zugriff, obwohl sie es könnten. } auto&& from_ptr(this auto&& self) { if (!self.ptr) throw std::bad_optional_access{}; return std::forward_like<decltype(self)>(*self.ptr); // Es ist nicht empfehlenswert, *std::forward<decltype(self)>(self).ptr zu verwenden, weil // std::unique_ptr<TypeTeller> dereferenziert immer zu einem nicht-konstanten L-Wert. } }; int main() { FarStates my_state { .ptr{std::make_unique<TypeTeller>()}, .opt{std::in_place, TypeTeller{}}, .container{std::vector<TypeTeller>(1)}, }; my_state.from_ptr()(); my_state.from_opt()(); my_state[0](); std::cout << '\n'; std::as_const(my_state).from_ptr()(); std::as_const(my_state).from_opt()(); std::as_const(my_state)[0](); std::cout << '\n'; std::move(my_state).from_ptr()(); std::move(my_state).from_opt()(); std::move(my_state)[0](); std::cout << '\n'; std::move(std::as_const(my_state)).from_ptr()(); std::move(std::as_const(my_state)).from_opt()(); std::move(std::as_const(my_state))[0](); std::cout << '\n'; }
Ausgabe:
mutable lvalue mutable lvalue mutable lvalue const lvalue const lvalue const lvalue mutable rvalue mutable rvalue mutable rvalue const rvalue const rvalue const rvalue
Siehe auch
|
(C++11)
|
wandelt das Argument in einen xvalue um
(Funktions-Template) |
|
(C++11)
|
leitet ein Funktionsargument weiter und verwendet den Typ-Template-Parameter, um seine Wertkategorie zu erhalten
(Funktions-Template) |
|
(C++17)
|
erhält eine Referenz auf
const
zu seinem Argument
(Funktions-Template) |