C'est une sorte d' arc-boutée-init-liste. [dcl.init.liste]/1.3
Pour être encore plus précis, c'est un " expr-ou-calé-init-liste [dcl.init]/1
d'une instruction return " [stmt.retour]/2
Une instruction de retour avec un autre opérande doit être utilisé uniquement dans un
fonction dont le type de retour n'est pas cv vide; l'instruction de retour
initialise le glvalue résultat ou prvalue objet de résultat de l'
(explicite ou implicite) d'appel de fonction par copier-initialisation de la
l'opérande.
À partir de ce point, permettez-moi de qoutes xskxzr réponse qui mentionnent [classe.copie.élision]/3
Dans la suite de la copie de l'initialisation de contextes, une opération de déplacement peut être utilisé à la place d'une opération de copie:
- Si l'expression dans une instruction de retour ([stmt.retour]) est un (éventuellement entre parenthèses) id-expression désignant un objet avec stockage automatique de la durée déclarée dans le corps ou le paramètre-déclaration de la clause d'enfermer les plus secrets de la fonction ou de la lambda-expression, ou
Normale de la parole humaine, la raison pour laquelle la copie est appelée à la place de bouger car l'embrassa-init-liste d'appels u
qui est arrivé à être lvalue.
Ainsi, vous pouvez veux savoir si moisa-init-liste d'appels u
qui est rvalue ...
return {std::move(u)};
Eh bien, u
est déplacé vers un nouveau rvalue d' UserName
et copie élision travaille juste après.
Donc, cela prend un coup comme dans
return u;
godbolt.org/g/b6stLr
wandbox.org/permlink/7u1cPc0TG9gqToZD
#include <iostream>
#include <optional>
struct UserName
{
int x;
UserName() : x(0) {};
UserName(const UserName& other) : x(other.x) { std::cout << "copy " << x << "\n"; };
UserName(UserName&& other) : x(other.x) { std::cout << "move " << x << "\n"; };
};
std::optional<UserName> CreateUser()
{
UserName u;
return u; // this one moves UserName
}
std::optional<UserName> CreateUser_listinit()
{
UserName u;
auto whatever{u};
return whatever;
}
std::optional<UserName> CreateUser_listinit_with_copy_elision()
{
UserName u;
return {u};
}
std::optional<UserName> CreateUser_move_listinit_with_copy_elision()
{
UserName u;
return {std::move(u)};
}
int main()
{
std::cout << "CreateUser() :\n";
[[maybe_unused]] auto d = CreateUser();
std::cout << "\nCreateUser_listinit() :\n";
[[maybe_unused]] auto e = CreateUser_listinit();
std::cout << "\nCreateUser_listinit_with_copy_elision() :\n";
[[maybe_unused]] auto f = CreateUser_listinit_with_copy_elision();
std::cout << "\nCreateUser_move_listinit_with_copy_elision() :\n";
[[maybe_unused]] auto g = CreateUser_move_listinit_with_copy_elision();
}
imprimer
CreateUser() :
move 0
CreateUser_listinit() :
copy 0
move 0
CreateUser_listinit_with_copy_elision() :
copy 0
CreateUser_move_listinit_with_copy_elision() :
move 0