在C ++ 11标准的第23.3.6.2节[vector.cons]中,如下所述:
template <class InputIterator>
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());
9 效果:使用指定的分配器构造一个等于范围
[first,last)
的向量。
10 复杂性:仅对N的复制构造函数进行N次调用(其中N是first
和last
之间的距离)如果迭代器的第一个和最后一个是向前的,则不进行重新分配,双向或随机访问类别。如果它们只是输入迭代器,它会使命令N调用T的复制构造函数和命令log(N)重新分配。
(此文本也存在于较旧的标准中)。一方面,它不要求解除引用InputIterator
应该导致存储在向量中的相同类型的值。另一方面,它讲述了使用复制构造函数,这种类型暗示了相同的类型。
我的问题是:如果可以在类型之间进行转换,那么使用此构造函数的不同类型的元素序列是否有效?需要参考该标准。
例如,以下代码正常at ideone。它是由标准保证,还是GCC恰好允许它?
#include <vector>
#include <iostream>
struct A {
int n;
A(int n_) : n(n_) {}
};
int main() {
int arr[] = {1,2,3,4,5,6,7,8,9,10};
std::vector<int> int_vec(arr, arr+10);
std::vector<A> A_vec(int_vec.begin(), int_vec.end());
for( std::vector<A>::iterator it=A_vec.begin(); it!=A_vec.end(); ++it )
std::cout<< it->n <<" ";
std::cout<<std::endl;
}
答案 0 :(得分:11)
来自C ++ Jan 2012草案:
§23.2.3/ 3 [sequence.reqmts] .... i和j表示满足输入迭代器的迭代器 要求和指可隐式转换为的元素 value_type ,[i,j)表示有效范围....
X(i,j)
X a(i,j)
需要:T应该是EmplaceConstructible到X. 来自* i。对于vector,如果迭代器不符合前向 迭代器要求(24.2.5),T也应该是MoveInsertable到X. 范围[i,j)中的每个迭代器应该只被解除引用一次 post :distance(begin(),end())== distance(i,j)构造一个序列 容器等于范围[i,j)
Coren让我注意到你所引用的部分:
§23.3.6.2/8[vector.cons]
template <class InputIterator> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
效果:使用指定的分配器构造一个等于[first,last]范围的向量。
复杂性:仅对T 的复制构造函数进行N 调用(其中N是第一个和最后一个之间的距离),如果迭代器的第一个和最后一个是正向的,则不进行重新分配或随机访问类别。如果它们只是输入迭代器,它会使命令N调用T的复制构造函数和命令log(N)重新分配。
位于矢量特定区域,技术上应覆盖第一部分。但是,我相信这个对复制构造函数的引用是错误的,并且是迂腐的,提到复制构造函数的复杂性是最大的,因此0调用复制构造函数(仅使用转换构造函数)在我看来是有效的。这不像我希望的那么清晰。
Xeo让我注意到这样一个事实:C++ Standard Core Language Active Issues, Revision 78有一个问题(535)是关于如何在标准中“关于复制结构的许多规定仅用于指代“复制构造函数。”'这显然是不好的措辞。“应该检查标准中”复制构造函数“一词的每次使用,以确定它是否严格适用于复制构造函数或任何用于复制的构造函数。 (类似的问题适用于“复制赋值运算符”,它与赋值运算符函数模板具有相同的关系。)“因此,纠正这种不良措辞是在他们的待办事项清单上。
答案 1 :(得分:1)
你甚至可以走得更远。这段代码也可以正常工作:
#include <vector>
#include <iostream>
struct A {
int n;
int v;
A(int n_, int v_ = 0) : n(n_), v(v_) {}
};
int main() {
int arr[] = {1,2,3,4,5,6,7,8,9,10};
std::vector<A> A_vec(arr, arr+10);
for( std::vector<A>::iterator it=A_vec.begin(); it!=A_vec.end(); ++it )
std::cout<< it->n <<" ";
std::cout<<std::endl;
}
正如您在标准中所述,§23.3.6.2:
仅对N
的复制构造函数进行N次调用
=&GT;这个构造函数迭代每个元素并使用复制构造函数,因此,只要你有一个工作的复制构造函数,它就可以在每个编译器上正常工作。
答案 2 :(得分:0)
由于编译器无法区分尝试使用类型X的复制构造函数和尝试使用带X的构造函数,所以
的任何实现 template <class InputIterator>
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());
必须在所有编译器中工作。
[编辑]看起来需要更多解释。 如何实现上面的Vector构造函数?
template <class InputIterator>
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator())
{
for(InputIterator i = first; i != last; i++)
{
push_back(*i); // Or whatever way to add to vector.
}
}
现在任何去引用并尝试添加它本地容器存储*我将导致类型* i的复制构造函数(让我们说类型T(即向量)。换句话说,实现必须使对象* i的副本并将其添加到内部对象集合(无论它是什么)。 因此,模板定义/实现最终将扩展为“T x(* i)”。这里的病房只是一个语言方面。 C ++不区分* i是否实际上是类型T或* i是可以隐式转换为T的类型。
这不需要在标准中明确说明。