2010-08-12 25 views
6

en C++ que está bien tener un funcction que tiene una función de tipo de locales:¿Por qué las plantillas no pueden tomar tipos locales de funciones?

int main() { 
    struct S { static void M(const S& s) { } }; 
    S s; 
    S::M(s); 
} 

pero no bien tener una plantilla que hace:

template<typename T> void Foo(const T& t) { } 

int main() { 
    struct S { } s; 
    Foo(s); // Line 5: error: no matching function for call to 'Foo(main()::S&)' 
} 

14.3.1 paragraph 2 in the c++ standard.

Un tipo sin vinculación [...] no se utilizará como argumento de plantilla para una plantilla tipo-parámetro

¿Por qué C++ no permite eso?


La mejor explicación que he oído hasta ahora es que los tipos de interiores tienen ninguna vinculación y que esto podría implicar que una función que les toma como arg debe tener ninguna vinculación. Pero no hay ninguna razón por la que pueda ver que una instanciación de plantilla debe tener un vínculo.


p.s. No digas "thats not allowed because the standard says it's not"

+5

No hay una buena razón, y C++ 0x eliminará esta restricción (pero no la que está vinculada en las páginas, todavía no tengo ni idea de por qué no está permitido). –

+0

@Mike; ¡Corto y al grano! – BCS

Respuesta

3

Supongo que es porque requeriría que la plantilla se instanciara efectivamente dentro del alcance de la función, ya que es donde tales tipos son visibles. Sin embargo, al mismo tiempo, se supone que las instancias de plantilla actúan como si estuvieran en el ámbito en el que se define la plantilla. Estoy seguro de que esto es posible lidiar con eso de alguna manera, pero si estoy en lo cierto, el organismo de estándares decidió no poner esa carga en los escritores de compilación.

Una decisión similar fue la razón por la que vector<vector<int>> es una sintaxis no válida según el estándar; detectar que la construcción requiere alguna interacción entre las fases del analizador y del analizador. Sin embargo, eso está cambiando, porque los estándares de C++ 0x encontraron que todos los compiladores lo están detectando de todos modos para emitir mensajes de error.

Sospecho que si se demostrara que permitir esta construcción fue trivial de implementar, y que no introdujo ninguna ambigüedad en las reglas de determinación del alcance del idioma, es posible que algún día vea el estándar cambiado aquí también.

+1

"Algún día" será tan pronto como se ratifique C++ 0x, a menos que cambien de opinión. El borrador final elimina esta restricción. –

+0

Podría imaginarme una arquitectura de compilación en la que sería difícil implementarla, pero también puedo pensar en las que tendría de manera gratuita. – BCS

7

Creo que la dificultad que se preveía era con dos ejemplos de Foo<T> que en realidad significan cosas completamente diferentes, porque T no era lo mismo para ambos. Bastantes implementaciones tempranas de plantillas (incluida la de cfront) usaban un repositorio de instancias de plantillas, de modo que el compilador podía instanciar automáticamente una plantilla sobre un tipo requerido cuando/si se descubría que una instancia sobre ese tipo no estaba ya en el repositorio.

Para que funcione con tipos locales, el repositorio no solo podría almacenar el tipo sobre el que se creó la instancia de la plantilla, sino que debería hacer algo como crear una "ruta" completa para el tipo de la instanciación. Si bien es probable que sea posible, creo que se consideró mucho trabajo adicional con muy poco (o ningún) beneficio real.

Desde entonces, las reglas han cambiado lo suficiente como para que el compilador haga algo equivalente, encontrando (y fusionando) instancias sobre el mismo tipo en diferentes lugares (incluso a través de TU) para que dos instancias de foo<int> (por ejemplo) no violen la ODR.En base a esa realización, la restricción se ha aflojado en (el borrador actual de) C++ 0x (aún no se puede instanciar una clase de plantilla sobre un tipo local, pero puede usar un tipo local como parámetro para una función de plantilla) .

+0

En resumen, ¿solía haber más trabajo para el compilador? – BCS

+0

@BCS: Si bien eso también es cierto, no es * tanto * que solía ser más trabajo para el compilador, ya que es 1) que la mayor parte del trabajo adicional ahora se realiza por otros motivos de todos modos, y 2) compilar C++ ahora es tan complejo que la gente está más dispuesta a aceptar agregar aún más complejidad, siempre y cuando no sea demasiado drástica. –

+0

§14.3.1 [temp.arg.type] tiene varios ejemplos de pasar tipos locales a una plantilla de clase. – Potatoswatter

Cuestiones relacionadas