F
@DNKpp sagte in Parameterpack verändern:
@Finnegan sagte in Parameterpack verändern:
Ich denke du hast da noch einen Fehler drin:
template<typename T>
replacement_forward_type_t<T> replace_forward( T& param )
sollte stattessen:
template<typename T>
replacement_forward_type_t<T> replace_forward( T&& param )
Das stimmt so nicht ganz. Da er keine automatische deduction nutzt, sondern den Typen selbst angibt, erhält er in ersterem Fall garantiert immer eine lvalue-ref. Jedoch übergibt er param in den gezeigten Fällen auch immer nur als lvalue-ref. Würde initial an execute eine rvalue-ref übergeben werden, würde es durch die manuelle Angabe von T mit deiner vorgeschlagenen Variante nicht compilen, da param dann entsprechend eine rvalue-ref erwarten würde.
=> https://godbolt.org/z/x31cv3KjP
Oh ja, das stimmt! Das ist ja eine forward-Implementation, die die Typangabe im Template-Argument erwartet. Da bin ich auch echt einiger Verwirrung zum Opfer gefallen indem ich von Deduktion ausgegangen bin
Ich war auf replacement_forward_type_t<T> fixiert, das meines Erachtens immer ein Alias für T&& ist, wenn es sich nicht um einen String handelt. Das kann auch nicht richtig sein, oder? Die Idee ist doch, nur selektiv eine RValue-Referenz zurückzugeben, und zwar dann, wenn auch das "Original" eine ist. Sonst kommt z.B. eine Funktion, der ich eine Variable via replace_forward übergebe auf die Idee, aus der Variable zu "moven" (?).
EDIT: Ich weiß nicht ob ich dich richtig verstehe aber deine Erklärung scheint mir hier auch nicht ganz richtig zu sein:
Erstmal Deduktion versuchen und den Unterschied zwischen Deduktion via auto und delctype(auto) kennen. Letzteres ist oft hilfreich, wenn man deduzieren und dabei die Referenz erhalten will. auto-Deduktion liefert dir nämlich immer den reinen Typ ohne die Referenz.
Es ist zwar korrekt, dass auto immer eine value daduced, aber decltype(auto) deduced nicht garantiert eine Referenz, sondern kann auch eine Value sein! Möchtest du eine Referenz haben, dann sollte man auch zu auto&& greifen.
Allerdings ist das für den hier gezeigten Anwendungsfall wohl genau das was er haben will: Referenz oder Value.
Ich meinte damit nicht, dass immer eine Referenz deduziert wird, sondern dass diese erhalten bleibt, wenn das Original bereits eine ist.
Was ist denn, wenn wir bei meinem Vorschlag anders herum gehen und eben nicht sagen, dass es eine "forward"-Implementation ist, sondern eine deduzierende Ersetzungs-Funktion? Das ist das, worauf in intuitiv eigentlich hinaus wollte. Damit, ein "forward" zu bauen war ich eh nicht so besonders glücklich (habe mich da an vorherigen Lösungen orientiert):
template<typename T>
auto replace( T&& param ) -> decltype(auto)
{
if constexpr( is_string_ref_v<T> )
{
return std::string( "Replaced" );
}
else if constexpr( is_char_array_ref_v<T> )
{
return std::string( "Replaced" );
}
else if constexpr( is_char_pointer_ref_v<T> )
{
return std::string( "Replaced" );
}
else
{
return std::forward<T>( param );
}
}
Das verwendet man dann so (aus dem ersten Post):
template<typename ...Params>
void execute(std::string const& name, Params&&... params)
{
impl()->execute(name, replace(std::forward<Params>(params))...);
}
Sollte das nicht funktionieren? std::forward übergibt Parameter in der Value Category die an execute übergeben wurde, replace ersetzt Strings und gibt dann eine RValue-Referenz auf std::string-Objekte zurück und "reflektiert" ansonsten den Parameter in derselben Value Category?