5

Si hago un puntero-a-miembro-base, puedo convertirlo generalmente en un puntero-a-miembro-derivado, pero no cuando lo uso dentro de una plantilla como Buzz a continuación, donde el primer argumento de plantilla influye en el segundo. ¿Estoy luchando contra los errores del compilador o el estándar realmente exige que esto no funcione?¿Por qué no puedo bajar el puntero a miembros en argumentos de plantilla?

struct Foo 
{ 
    int x; 
}; 

struct Bar : public Foo 
{ 
}; 

template<class T, int T::* z> 
struct Buzz 
{ 
}; 

static int Bar::* const workaround = &Foo::x; 

int main() 
{ 
    // This works. Downcasting of pointer to members in general is fine. 
    int Bar::* y = &Foo::x; 

    // But this doesn't, at least in G++ 4.2 or Sun C++ 5.9. Why not? 
    // Error: could not convert template argument '&Foo::x' to 'int Bar::*' 
    Buzz<Bar, &Foo::x> test; 

    // Sun C++ 5.9 accepts this but G++ doesn't because '&' can't appear in 
    // a constant expression 
    Buzz<Bar, static_cast<int Bar::*>(&Foo::x)> test; 

    // Sun C++ 5.9 accepts this as well, but G++ complains "workaround cannot 
    // appear in a constant expression" 
    Buzz<Bar, workaround> test; 

    return 0; 
} 

Respuesta

5

Simplemente no está permitido. De acuerdo con §14.3.2/5:

Las siguientes conversiones se realizan en cada expresión utilizada como plantilla-argumento sin tipo. Si un argumento de plantilla sin tipo no se puede convertir al tipo del parámetro de plantilla correspondiente, entonces el programa está mal formado.
- para un parámetro de plantilla sin tipo de tipo integral o de enumeración, se aplican promociones integrales (4.5) y conversiones integrales (4.7).
- para un parámetro de plantilla sin tipo de tipo puntero a objeto, se aplican las conversiones de calificación (4.4) y la conversión de matriz a puntero (4.2). - Para un parámetro de plantilla sin tipo de tipo referencia al objeto, no se aplican conversiones. El tipo al que hace referencia la referencia puede estar más calificado que el tipo (por lo demás idéntico) del argumento de la plantilla. El parámetro de plantilla está ligado directamente al argumento de plantilla, que debe ser un valor l.
- Para un parámetro de plantilla sin tipo de tipo puntero a función, solo se aplica la conversión de función a puntero (4.3). Si el argumento de plantilla representa un conjunto de funciones sobrecargadas (o un puntero a tal), la función de coincidencia se selecciona del conjunto (13.4).
- Para un parámetro de plantilla sin tipo de tipo referencia a función, no se aplican conversiones. Si el argumento de la plantilla representa un conjunto de funciones sobrecargadas, la función de coincidencia se selecciona del conjunto (13.4).
- Para un parámetro de plantilla sin tipo de tipo puntero a función de miembro, no se aplican conversiones. Si el argumento de plantilla representa un conjunto de funciones de miembro sobrecargadas, la función de miembro coincidente se selecciona del conjunto (13.4).
- Para un parámetro de plantilla sin tipo de tipo puntero a miembro de datos, se aplican las conversiones de calificación (4.4).

He enfatizado la conversión con respecto al puntero a los miembros de datos. Tenga en cuenta que su conversión (§4.11/2) no figura en la lista. En C++ 0x, sigue siendo el mismo a este respecto.

+0

Definitivamente, ¿pero alguna idea de por qué no está permitido? Parece arbitrario. –

+1

@Joseph: pensé que también, por lo que también revisé C++ 0x. (Eliminaron muchas decisiones aparentemente arbitrarias, como no tener parámetros de plantilla predeterminados para las plantillas de funciones). O nadie encontró un uso para él y, por lo tanto, no ha cambiado realmente/simplemente no se presionó (es más fácil agregar un pozo). característica probada que desaprobar una característica rota), o hay alguna razón fundamental que simplemente no puedo ver. – GManNickG

Cuestiones relacionadas