2012-01-03 17 views
26

Por ejemplo uninitialized_copy se define en la norma como:¿Debería la implementación protegerse contra la sobrecarga de coma?

Efectos:

for (; first != last; ++result, ++first) 
    ::new (static_cast<void*>(&*result)) 
    typename iterator_traits<ForwardIterator>::value_type(*first); 

Si entenderse literalmente, esto es un requisito para llamar operator ,(ForwardIterator, InputIterator). Y, de hecho, este código imprime Hello world! diez veces:

#include <memory> 
#include <iterator> 
#include <iostream> 

using namespace std; 

namespace N {  
    struct X : iterator<forward_iterator_tag, int> { 
     pointer _p; 
     X(pointer p) : _p(p) {} 
     X& operator++() { ++_p; return *this; } 
     X operator++(int) { X r(*this); ++_p; return r; } 
     reference operator*() const { return *_p; } 
     pointer operator->() const { return _p; } 
    }; 

    bool operator==(X a, X b) { return a._p == b._p; } 
    bool operator!=(X a, X b) { return !(a == b); } 

    void operator,(X a, X b) { cout << "Hello world!\n"; } 
} 

int a[10], b[10]; 

int main() 
{ 
    using N::X; 
    uninitialized_copy(X(a), X(a+10), X(b)); 
} 

Sin embargo, para la mayoría de otros algoritmos de la norma da la descripción en prosa. P.ej. para copy, no es necesario llamar al operador ,. Pero si cambio

uninitialized_copy(X(a), X(a+10), X(b)); 

en el código anterior para

copy(X(a), X(a+10), X(b)); 

continuación se Hello world!todavía imprimen diez veces. Los resultados mencionados son observables en ambos, VS2005 y GCC 4.3.4. Sin embargo, si escribo

mismatch(X(a), X(a+10), X(b)); 

lugar, a continuación, VS2005 imprime Hello world! diez veces, pero GCC no lo hace.

Desafortunadamente no pude encontrar donde la norma prohíbe la sobrecarga de operator, para tipos de iteradores. Por el contrario, prohíbe las implementaciones de hacer llamadas que el anterior [global.functions]:

A menos que se especifique lo contrario, las funciones globales y no miembros de la biblioteca estándar, no deberá usar las funciones de otro espacio de nombres que se encuentran a través búsqueda de nombres dependiente del argumento (3.4.2).

Entonces, ¿quién de las cuatro partes está equivocado: MSVC, GCC, ISO o yo? (Elija uno)

+3

Creo que Visual C++, gcc e ISO son todos incorrectos: Visual C++ y gcc no deberían estar usando el operador de coma, y ​​la especificación (ISO) no debería usar la coma en su código de ejemplo. Podría estar equivocado; eso es solo mi primer pensamiento al respecto. (Por favor, considere abrir un error de Visual C++ en [Microsoft Connect] (https://connect.microsoft.com/VisualStudio); al menos vale la pena llamar su atención.) –

+2

Dado que incluso algo así como 'Size' es un tipo de plantilla , Le doy la vuelta al argumento y digo que el estándar quiere * precisamente * lo que dice, y si ve razón para proporcionar un operador de coma personalizado, entonces se le invita a hacerlo, y obtendrá el comportamiento especificado . –

+0

@JamesMcNellis KerrekSB: Gracias. Espero que alguien pueda encontrar un lugar donde se dice que es un comportamiento indefinido, de lo contrario tenemos tres informes de errores para abrir. – ybungalobill

Respuesta

3

Buena captura. Creo en mi humilde opinión que la intención del comité ISO era que se siguiera la §3.4.2. La semántica sugerida de uninitialized_copy se interpreta erróneamente como si se requiriera llamar a la coma. Y las implementaciones no deberían usarlo (Informaría un error a gcc btw).

+3

Esta es mi interpretación también. La sobrecarga de comas es una locura y creo que simplemente pasó de largo la atención de los miembros de nuestro comité. –

+0

Sí, desde entonces envié un PR y AFAIK que arreglaron el estándar y las implementaciones populares siguieron eliminando las llamadas no deseadas del operador de coma. – ybungalobill

Cuestiones relacionadas