Les tableaux peuvent être initialisés avec ce qu'on appelle une liste d'initialisation.
Par exemple:
int my_array[3] = {10, 20, 30};
C'est très utile lorsque nous avons un ensemble de valeurs initiales pour notre tableau. Cependant, cette approche ne fonctionne pas pour attribuer de nouvelles valeurs au tableau une fois qu'il est déclaré.
my_array = {10, 20, 30};
error: assigning to an array from an initializer list
Cependant, nous avons parfois des processus où nous devons initialiser nos tableaux plusieurs fois à certaines valeurs initiales (par exemple: à l'intérieur d'une boucle), donc je pense qu'il serait très utile de pouvoir utiliser des listes d'initialiseurs pour attribuer des valeurs aux variables déjà déclarées.
Ma question est: y a-t-il une raison pour avoir une telle fonctionnalité au moment de la déclaration mais pas une fois que le tableau est déclaré? Pourquoi ça marche dans un cas mais pas dans l'autre?
Les tableaux sont des citoyens de seconde classe en C++. Ce sont des objets , mais ils sont sévèrement restreints: ils ne peuvent pas être copiés, ils sont décomposés en pointeurs dans divers contextes, etc. Envisagez d'utiliser std::array
, qui est un wrapper (de taille fixe) au-dessus des tableaux intégrés, mais est un citoyen de première classe qui prend en charge diverses fonctionnalités pratiques:
std::array<int, 3> my_array = {10, 20, 30};
my_array = {40, 50, 60};
Cela fonctionne parce que, par [array.overview]/2 ,
std::array
est un type d'agrégat qui peut être initialisé par liste avec jusqu'àN
éléments dont les types sont convertibles enT
.
Cela fonctionne également avec std::vector
. Les vecteurs sont une histoire différente, donc je ne vais pas entrer dans les détails ici.
Si vous préférez insister sur les tableaux intégrés, voici une solution de contournement que j'ai conçue pour permettre l'attribution d'une liste de valeurs à un tableau intégré (en respectant les catégories de valeurs), en utilisant des techniques de métaprogrammation de modèle. Une erreur de compilation est (correctement) déclenchée si la longueur du tableau et la liste de valeurs ne correspondent pas. (Merci au commentaire de Caleth pour l'avoir signalé!) Notez que la copie de tableaux intégrés est impossible en C++; c'est pourquoi nous devons passer le tableau à la fonction.
namespace detail {
template <typename T, std::size_t N, std::size_t... Ints, typename... Args>
void assign_helper(T (&arr)[N], std::index_sequence<Ints...>, Args&&... args)
{
((arr[Ints] = args), ...);
}
}
template <typename T, std::size_t N, typename... Args>
void assign(T (&arr)[N], Args&&... args)
{
return detail::assign_helper(arr, std::make_index_sequence<N>{}, std::forward<Args>(args)...);
}
Et pour l'utiliser:
int arr[3] = {10, 20, 30};
assign(arr, 40, 50, 60);
Maintenant, arr
se compose de 40, 50, 60
.
Les tableaux peuvent être initialisés avec ce qu'on appelle une liste d'initialisation.
Et bien non.
Une classe peut être initialisée avec une liste d'initialisation, ils doivent avoir un constructeur qui prend un std::initializer_list
.
Exemple :
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator());
Les tableaux ne sont pas une classe, ils ne peuvent donc pas avoir de constructeur. Mais ils peuvent être initialisés avec initialisation agrégée :
Un agrégat est l'un des types suivants:
- type de tableau
- ...
Et comme L.F. a dit: Ils ne peuvent pas être copiés:
Affectation
Les objets de type tableau ne peuvent pas être modifiés dans leur ensemble: même s'il s'agit de valeurs l (par exemple, une adresse de tableau peut être prise), ils ne peuvent pas apparaître sur le côté gauche d'un opérateur d'affectation
Source: https://en.cppreference.com/w/cpp/language/array
C'est pourquoi le {}
la syntaxe fonctionne pour l'initialisation et non pour l'affectation, car cela ne signifie pas la même chose.
Y a-t-il une raison pour avoir une telle fonctionnalité au moment de la déclaration mais pas une fois que le tableau est déclaré? Pourquoi cela fonctionne-t-il dans un cas mais pas dans l'autre?
La syntaxe x = {a, b, ...}
Implique un type spécifique de listes d'initialisation appelé copy-list-initialization. Le cppreference mentionne les façons possibles d'utiliser l'initialisation de la liste de copie:
T object = {arg1, arg2, ...};
(6)function( { arg1, arg2, ... } )
(7)return { arg1, arg2, ... } ;
(8)object[ { arg1, arg2, ... } ]
(9)object = { arg1, arg2, ... }
(10)U( { arg1, arg2, ... } )
(11)Class { T member = { arg1, arg2, ... }; };
(12)La syntaxe de tableau que vous avez essayée T myArr[] = {a, b, c...}
Fonctionne et est numérotée comme (6) initialisation d'une variable nommée avec une liste d'initiation contreventée après un signe égal.
La syntaxe qui ne fonctionne pas pour vous (myArr = {a, b, ...}
) Est numérotée comme (10) et elle s'appelle list- initialisation dans une expression d'affectation. La chose à propos des expressions d'affectation est que le côté gauche doit être un soi-disant lvalue, et bien que les tableaux soient des valeurs l, ils ne peuvent pas apparaître sur le côté gauche des affectations selon la spécification .
Cela étant dit, il ne serait pas très difficile de contourner l'affectation en copiant une liste d'initialisation sur le tableau en tant que telle:
#include <algorithm>
#include <iostream>
int main() {
int arr[] = {1, 2, 3};
auto itr = arr;
auto assign = {5, 2, 1};
std::copy(assign.begin(), assign.end(), itr);
}