这是一个相当棘手的问题,可能是 VisualStudio 是对的,而 Comeau 是错的(这似乎很难相信)。
标准如果逐字阅读,根据复制构造函数定义向量构造函数(见引号),字面意思是通过取消引用迭代器获得的对象必须首先转换为类型 T 然后复制构造函数应该是叫。此时,使用显式构造函数的代码不应编译。
另一方面,期望一个实现直接调用一个将解引用的迭代器作为参数的构造函数似乎是合理的,在这种情况下,构造函数调用将是显式的,因此代码应该编译。这将与下面引用中的确切措辞背道而驰,因为复制构造函数是为给定类型 T 定义的,作为一个构造函数,该构造函数对 T 类型的对象进行单个可能的常量引用。
我想不出任何不使用 Comeau 方法的合理论据,并且我认为(这只是个人意见)是标准中关于向量构造函数复杂性的措辞可能应该重述为只需要 N 次调用适当的 T 构造函数,在适当的情况下,必须定义为与调用匹配的构造函数T( *first )
(即,采用InputIterator::value_type
(按值或可能的常量引用)的构造函数,或者从隐式转换InputIterator::value_type
为 T后的 T 复制构造函数。
23.2.4.1 [lib.vector.cons]/1
复杂性:构造函数模板向量(InputIterator first, InputIterator last) 仅对 T 的复制构造函数进行 N 次调用(其中 N 是 first 和 last 之间的距离),如果 iterator first 和 last 是前向、双向或随机的,则不会重新分配访问类别。如果它们只是输入迭代器,它将对 T 的复制构造函数进行 N 次调用,并对日志 N 次重新分配进行排序。
我想知道 VS 编译器在给出时的行为:
struct T1;
struct T2 {
operator T1 ();
};
struct T1 {
T1( T2 const & ) { std::cout << "T1(T2)" << std::endl; }
};
T2::operator T1() {
std::cout << "T2::operator T1" << std::endl;
return T1(*this);
}
int main() {
std::vector<T2> v2;
v2.push_back( T2() );
std::vector<T1> v1( v2.begin(), v2.end() );
}
使用 g++ 的结果是T2::operator T1
不调用,而是v1
直接从v2
. 我假设使用 VS,编译器将使用T2::operator T1
将每个元素转换v2
为 T1 元素,然后调用复制构造函数。是这样吗?