Это довольно сложный вопрос, и, возможно, дело в том, что VisualStudio прав, а Comeau неправ (в это, кажется, трудно поверить).
Стандарт, читаемый слово за словом, определяет этот векторный конструктор в терминах конструктора копирования (см. Цитату), и это буквально означает, что объект, полученный путем разыменования итератора, должен сначала быть преобразован в введите T, а затем должен быть вызван конструктор копирования. На этом этапе с явным конструктором код не должен компилироваться.
Представляется разумным ожидать, что реализация, с другой стороны, будет напрямую вызывать конструктор, принимая в качестве аргумента разыменованный итератор, и в этом случае вызов конструктора будет явным, и, следовательно, код должен компилироваться. Это пошло бы против точной формулировки в приведенной ниже цитате, так как конструктор копирования определен для данного типа T как конструктор, который принимает одну, возможно, постоянную ссылку на объект типа T.
Я не могу придумать ни одного разумного аргумента, чтобы не использовать подход Comeau, и я считаю (это всего лишь личное мнение), что формулировка в стандарте относительно сложности векторного конструктора, вероятно, должна быть переформулирована как требующая только N обращений к соответствующему T-конструктору , где это необходимо, должно быть определено как конструктор, который соответствует вызову T( *first )
(то есть либо конструктор, принимающий InputIterator::value_type
(по значению, либо, возможно, постоянная ссылка ) или конструктор T-копии после неявного преобразования из InputIterator::value_type
в T.
23.2.4.1 [lib.vector.cons] / 1
Сложность: вектор шаблона конструктора (InputIterator
первый, InputIterator последний) делает только
N обращений к копирующему конструктору T
(где N - расстояние между
первое и последнее) и никаких перераспределений
если итераторы первый и последний имеют
вперед, двунаправленный или случайный
Категории доступа. Это делает заказ N
вызывает конструктор копирования T и
порядок журнала 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, а затем вызвать конструктор копирования. Это так?