昨天一个朋友问我,array为什么可以这样写
boost::array<int,4> a = { 1, 2, 3, 4 };
答: 重载了赋值操作符,通过类的缺省构造给赋值操作一个右值来初始化一个array变量。 至于为什么要这样做,而不直接初始化?这是为了语法形式上能够与原生数组相符合。我自以为如此就回答了这个问题 。
朋友突然再问了一句,为什么可以这样缺省构造 ? 为什么可以 = { 1, 2, 3, 4 };
是啊! 为什么!
那一时我就象短路了一般,是啊,为什么,为什么我不记得! 过了自己好一会才缓过气,想起了答案。下面一起看一看这个问题
先看一看问题的代码,不论其它,只讨论初始化,boost::array代码被简化为:
那为什么 { 1, 2, 3, 4 } 可以缺省构造出一个 boost::array 呢,是由C++ 标准的哪个条款来完成的?
其实boost::array 的 Design Rationale 中有提到了这个问题。只是这个细节平时难得用到,也就从记忆里淡出了,吓了自己好大一跳。作者将boost::array实现为一个 "aggregate" (C++标准 8.5.1节 )。这意味着可以用下面的形式完成初始化。
boost::array<int,4> a = { { 1, 2, 3, 4 } };
而一个符合标准(8.5.1.11)的编译器也可以使用更少一些的大括号来完成初始化工作
boost::array<int,4> a = { 1, 2, 3, 4 };
具体的标准条款摘取了三条 copy 在下面,大家可以参考。本来想翻译一下,但最终一想还是算了,英文水平有限,藏拙的好 :-)
INTERNATIONAL STANDARD
ISO/IEC 14882
Second edition
2003-10-15
Programming languages — C++
8.5.1 Aggregates
1 An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected
non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).
2 When an aggregate is initialized the initializer can contain an initializer-clause consisting of a braceenclosed,
comma-separated list of initializer-clauses for the members of the aggregate, written in increasing
subscript or member order. If the aggregate contains subaggregates, this rule applies recursively to the members of the subaggregate. [Example:
struct A {
int x;
struct B {
int i;
int j;
} b;
} a = { 1, { 2, 3 } };
initializes a.x with 1, a.b.i with 2, a.b.j with 3. ]
11 Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the
succeeding comma-separated list of initializers initializes the members of a subaggregate; it is erroneous
for there to be more initializers than members. If, however, the initializer-list for a subaggregate does not
begin with a left brace, then only enough initializers from the list are taken to initialize the members of the
subaggregate; any remaining initializers are left to initialize the next member of the aggregate of which the
current subaggregate is a member. [Example:
float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
is a completely-braced initialization: 1, 3, and 5 initialize the first row of the array y[0], namely
y[0][0], y[0][1], and y[0][2]. Likewise the next two lines initialize y[1] and y[2]. The initializer
ends early and therefore y[3]’s elements are initialized as if explicitly initialized with an expression
of the form float(), that is, are initialized with 0.0. In the following example, braces in the initializerlist
are elided; however the initializer-list has the same effect as the completely-braced initializer-list of the
above example,
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
The initializer for y begins with a left brace, but the one for y[0] does not, therefore three elements from
the list are used. Likewise the next three are taken successively for y[1] and y[2]. —end example]
boost::array<int,4> a = { 1, 2, 3, 4 };
答: 重载了赋值操作符,通过类的缺省构造给赋值操作一个右值来初始化一个array变量。 至于为什么要这样做,而不直接初始化?这是为了语法形式上能够与原生数组相符合。我自以为如此就回答了这个问题 。
朋友突然再问了一句,为什么可以这样缺省构造 ? 为什么可以 = { 1, 2, 3, 4 };
是啊! 为什么!
那一时我就象短路了一般,是啊,为什么,为什么我不记得! 过了自己好一会才缓过气,想起了答案。下面一起看一看这个问题
先看一看问题的代码,不论其它,只讨论初始化,boost::array代码被简化为:
template<class T, std::size_t N> class array
{
public:
T elems[N]; // fixed-size array of elements of type T
public:
// assignment with type conversion
template <typename T2>
array<T,N>& operator= (const array<T2,N>& rhs)
{
std::copy(rhs.begin(),rhs.end(), begin());
return *this;
}
}
{
public:
T elems[N]; // fixed-size array of elements of type T
public:
// assignment with type conversion
template <typename T2>
array<T,N>& operator= (const array<T2,N>& rhs)
{
std::copy(rhs.begin(),rhs.end(), begin());
return *this;
}
}
那为什么 { 1, 2, 3, 4 } 可以缺省构造出一个 boost::array 呢,是由C++ 标准的哪个条款来完成的?
其实boost::array 的 Design Rationale 中有提到了这个问题。只是这个细节平时难得用到,也就从记忆里淡出了,吓了自己好大一跳。作者将boost::array实现为一个 "aggregate" (C++标准 8.5.1节 )。这意味着可以用下面的形式完成初始化。
boost::array<int,4> a = { { 1, 2, 3, 4 } };
而一个符合标准(8.5.1.11)的编译器也可以使用更少一些的大括号来完成初始化工作
boost::array<int,4> a = { 1, 2, 3, 4 };
具体的标准条款摘取了三条 copy 在下面,大家可以参考。本来想翻译一下,但最终一想还是算了,英文水平有限,藏拙的好 :-)
INTERNATIONAL STANDARD
ISO/IEC 14882
Second edition
2003-10-15
Programming languages — C++
8.5.1 Aggregates
1 An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected
non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).
2 When an aggregate is initialized the initializer can contain an initializer-clause consisting of a braceenclosed,
comma-separated list of initializer-clauses for the members of the aggregate, written in increasing
subscript or member order. If the aggregate contains subaggregates, this rule applies recursively to the members of the subaggregate. [Example:
struct A {
int x;
struct B {
int i;
int j;
} b;
} a = { 1, { 2, 3 } };
initializes a.x with 1, a.b.i with 2, a.b.j with 3. ]
11 Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the
succeeding comma-separated list of initializers initializes the members of a subaggregate; it is erroneous
for there to be more initializers than members. If, however, the initializer-list for a subaggregate does not
begin with a left brace, then only enough initializers from the list are taken to initialize the members of the
subaggregate; any remaining initializers are left to initialize the next member of the aggregate of which the
current subaggregate is a member. [Example:
float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
is a completely-braced initialization: 1, 3, and 5 initialize the first row of the array y[0], namely
y[0][0], y[0][1], and y[0][2]. Likewise the next two lines initialize y[1] and y[2]. The initializer
ends early and therefore y[3]’s elements are initialized as if explicitly initialized with an expression
of the form float(), that is, are initialized with 0.0. In the following example, braces in the initializerlist
are elided; however the initializer-list has the same effect as the completely-braced initializer-list of the
above example,
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
The initializer for y begins with a left brace, but the one for y[0] does not, therefore three elements from
the list are used. Likewise the next three are taken successively for y[1] and y[2]. —end example]