为什么初始化列表只能用于声明?
Why can an initializer list only be used on declaration?
数组可以用所谓的初始化列表来初始化。
例如:
int my_array[3] = {10, 20, 30};
当我们的数组有一组初始值时,这非常有用。
但是,这种方法一旦声明就无法为数组分配新值。
my_array = {10, 20, 30};
error: assigning to an array from an initializer list
然而,有时我们在某些过程中需要将数组多次初始化为某些初始值(例如:在循环内),所以我认为能够使用初始化列表为变量赋值会非常有用已经申报了。
我的问题是:是否有理由在声明时有这样的功能,而不是在数组声明后?
为什么它在一种情况下有效而在另一种情况下无效?
数组是 C++ 中的 second-class 公民。
它们是对象,
但它们受到严格限制:
它们无法被复制,
它们在各种上下文中被分解为指针等。
考虑使用 std::array
,
这是内置数组顶部的 (fixed-size) 包装器,
但是是 first-class 支持各种便利功能的公民:
std::array<int, 3> my_array = {10, 20, 30};
my_array = {40, 50, 60};
这是有效的,因为根据 [array.overview]/2,
std::array
is an aggregate type that can be list-initialized with up
to N
elements whose types are convertible to T
.
这也适用于 std::vector
。
矢量是一个不同的故事,
所以这里就不细说了。
如果您更喜欢坚持使用内置数组,
这是我设计的解决方法
将值列表分配给内置数组
(尊重价值类别),
使用模板元编程技术。
compile-time 错误被(正确地)引发
如果数组的长度和值列表不匹配。
(感谢 Caleth 的
指出这一点的评论!)
请注意,在 C++ 中复制内置数组是不可能的;
这就是为什么我们必须将数组传递给函数。
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)...);
}
并使用它:
int arr[3] = {10, 20, 30};
assign(arr, 40, 50, 60);
现在 arr
由 40, 50, 60
.
组成
Arrays can be initialized with what's called an initialization list.
嗯,不。
A class 可以使用初始化列表进行初始化,它们必须具有采用 std::initializer_list
.
的构造函数
示例:
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator());
数组不是 class,因此它们不能有构造函数。但它们可以用 aggregate initialization:
初始化
An aggregate is one of the following types:
- array type
- ...
并且如 L.F. 所说:它们无法复制:
Assignment
Objects of array type cannot be modified as a whole: even though they
are lvalues (e.g. an address of array can be taken), they cannot
appear on the left hand side of an assignment operator
来源:https://en.cppreference.com/w/cpp/language/array
这就是为什么 {}
句法适用于初始化而不适用于赋值,因为它们的意思不同。
Is there a reason for having such a feature at declaration time but not once the array is declared? Why does it work in one case but not in the other case?
x = {a, b, ...}
语法涉及一种特定类型的初始化列表,称为 copy-list-initialization。 cppreference提到了使用copy-list初始化的可能方式:
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)
您尝试过的数组语法 T myArr[] = {a, b, c...}
有效并被记为 (6) 在等号 后使用 braced-init-list 初始化命名变量.
不适合您的语法 (myArr = {a, b, ...}
) 被编号为 (10),它被称为 list-initialization在赋值表达式中。关于赋值表达式的事情是左边必须是so-called左值,虽然数组是左值,但它们不能出现在赋值的左边as per the specification .
也就是说,通过将初始化列表复制到数组中来解决赋值问题并不难:
#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);
}
数组可以用所谓的初始化列表来初始化。
例如:
int my_array[3] = {10, 20, 30};
当我们的数组有一组初始值时,这非常有用。 但是,这种方法一旦声明就无法为数组分配新值。
my_array = {10, 20, 30};
error: assigning to an array from an initializer list
然而,有时我们在某些过程中需要将数组多次初始化为某些初始值(例如:在循环内),所以我认为能够使用初始化列表为变量赋值会非常有用已经申报了。
我的问题是:是否有理由在声明时有这样的功能,而不是在数组声明后? 为什么它在一种情况下有效而在另一种情况下无效?
数组是 C++ 中的 second-class 公民。
它们是对象,
但它们受到严格限制:
它们无法被复制,
它们在各种上下文中被分解为指针等。
考虑使用 std::array
,
这是内置数组顶部的 (fixed-size) 包装器,
但是是 first-class 支持各种便利功能的公民:
std::array<int, 3> my_array = {10, 20, 30};
my_array = {40, 50, 60};
这是有效的,因为根据 [array.overview]/2,
std::array
is an aggregate type that can be list-initialized with up toN
elements whose types are convertible toT
.
这也适用于 std::vector
。
矢量是一个不同的故事,
所以这里就不细说了。
如果您更喜欢坚持使用内置数组, 这是我设计的解决方法 将值列表分配给内置数组 (尊重价值类别), 使用模板元编程技术。 compile-time 错误被(正确地)引发 如果数组的长度和值列表不匹配。 (感谢 Caleth 的 指出这一点的评论!) 请注意,在 C++ 中复制内置数组是不可能的; 这就是为什么我们必须将数组传递给函数。
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)...);
}
并使用它:
int arr[3] = {10, 20, 30};
assign(arr, 40, 50, 60);
现在 arr
由 40, 50, 60
.
Arrays can be initialized with what's called an initialization list.
嗯,不。
A class 可以使用初始化列表进行初始化,它们必须具有采用 std::initializer_list
.
示例:
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator());
数组不是 class,因此它们不能有构造函数。但它们可以用 aggregate initialization:
初始化An aggregate is one of the following types:
- array type
- ...
并且如 L.F. 所说:它们无法复制:
Assignment
Objects of array type cannot be modified as a whole: even though they are lvalues (e.g. an address of array can be taken), they cannot appear on the left hand side of an assignment operator
来源:https://en.cppreference.com/w/cpp/language/array
这就是为什么 {}
句法适用于初始化而不适用于赋值,因为它们的意思不同。
Is there a reason for having such a feature at declaration time but not once the array is declared? Why does it work in one case but not in the other case?
x = {a, b, ...}
语法涉及一种特定类型的初始化列表,称为 copy-list-initialization。 cppreference提到了使用copy-list初始化的可能方式:
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)
您尝试过的数组语法 T myArr[] = {a, b, c...}
有效并被记为 (6) 在等号 后使用 braced-init-list 初始化命名变量.
不适合您的语法 (myArr = {a, b, ...}
) 被编号为 (10),它被称为 list-initialization在赋值表达式中。关于赋值表达式的事情是左边必须是so-called左值,虽然数组是左值,但它们不能出现在赋值的左边as per the specification .
也就是说,通过将初始化列表复制到数组中来解决赋值问题并不难:
#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);
}