2011-08-31 10 views
16

me Merily experimentando con los nuevos tipos de retorno de arrastre, donde conectó un problema con este código (simplificado)arrastran tipos de retorno, decltype y const-dad

#include <list> 

class MyContainer{ 
    std::list<int> ints; 

    auto begin() -> decltype(ints.begin()) 
    { 
    return ints.begin(); 
    } 

    auto begin() const -> decltype(ints.begin()) 
    { 
    return ints.begin(); 
    } 
}; 

Ignorar el hecho de cómo inútil este código es . La parte importante es el error del compilador genera cuando se utiliza gcc 4.6.1 (con -std=c++0x bandera):

In member function 'std::list<int>::iterator MyContainer::begin() const': 
error: could not convert '((const MyContainer*)this)->MyContainer::ints.std::list<_Tp, _Alloc>::begin [with _Tp = int, _Alloc = std::allocator<int>, std::list<_Tp, _Alloc>::const_iterator = std::_List_const_iterator<int>]()' from 'std::list<int>::const_iterator {aka std::_List_const_iterator<int>}' to 'std::list<int>::iterator {aka std::_List_iterator<int>}' 

En caso de que usted no está de fan de error relacionado con las plantillas, el cuento es que en el cuerpo de la const versión de MyContainer::begin, la expresión ints.begin() devuelve un valor de tipo std::list<int>::const_iterator (desde ints es const en ese contexto). Sin embargo, decltype(ints.begin()) produce el tipo std::list<int>::iterator, es decir, decltypeignora el calificador const del método begin al decidir el tipo de expresión. Como era de esperar, el resultado es un conflicto de tipos.

Esto me parece ser un error en el compilador de GCC. Solo tendría sentido para decltype cumplir con el calificador const y generar el tipo const_iterator. ¿Alguien puede confirmar o negar (quizás incluso explicar) esto? Tal vez estoy pasando por alto algo en la mecánica de decltype, pero este parece un escenario bastante sencillo.

Nota: hasta donde puedo decir, el mismo comportamiento se aplica no solo para std::list<int>, sino para cualquier tipo con funciones de miembro sobrecargadas en const -ness que devuelven tipos incompatibles.

+2

Compila sin error con una instantánea reciente de gcc 4.7.0. Hasta entonces, supongo que estás atrapado con 'ints.cbegin()' – Cubbi

+0

Por supuesto, en un caso tan trivial no era un obstáculo serio, pero es importante que gcc lo haga bien para todos los casos no triviales (I también quería asegurarme de que * I * lo entendiera bien; no deseo utilizar funciones que no entiendo). –

Respuesta

10

Tiene razón, este es un error. De acuerdo con N3291, sección 5.1.1, párrafo 3:

Si una declaración declara una plantilla de función función miembro o miembro de una clase X, la expresión se trata de una prvalue del tipo “puntero a CV-cali fi cador-ss X "entre el cv-qualifer-seq opcional y el final de la definición de función, miembro declarador o declarador. No aparecerá antes del cv-quali fi cador-seq opcional y no aparecerá dentro de la declaración de una función miembro estática (aunque su tipo y categoría de valor se definen dentro de una función de miembro estático ya que están dentro de una función miembro no estática) . [Nota: esto se debe a que la coincidencia de declaraciones no se produce hasta que se conoce el declarante completo. -finalización] A diferencia de la expresión de objeto en otros contextos, * no es necesario que sea de tipo completo para el acceso de los miembros de la clase (5.2.5) fuera del cuerpo de la función del miembro. [Nota: solo los miembros de la clase declarados antes de la declaración son visibles. -finalizar nota]

Pero esto fue un cambio reciente entre el último borrador en funcionamiento y N3291. Entonces GCC tenía razón hace menos de 6 meses; ese es el peligro de escribir código en una especificación móvil.

+0

Eso fue parte de mis pensamientos, ya que recordé alguna discusión sobre el último borrador y el uso de 'this' en un tipo de devolución posterior, pero no estaba seguro de si alguna de las propuestas allí fueron realmente aceptadas. Gracias por la respuesta bien referenciada. Afortunadamente (de acuerdo con el comentario de Cubby), GCC parece estar muy al tanto de esto, ya que la versión 4.7 ya aborda este cambio. –

Cuestiones relacionadas