2010-09-05 10 views
8

¿Cómo se puede realizar la auto funcionalidad de palabra clave sin usar el estándar C++ 0x?Plantilla automática hecha a mano (sin usar C++ 0x)

for(std::deque<std::pair<int, int> >::iterator it = points.begin(); 
    it != points.end(); ++it) 
{ 
    ... 
} 

Tal vez dicha clase:

class AUTO 
{ 
public: 
    template <typename T1> 
    AUTO(T1); 

    template <typename T2> 
    operator T2(); 
}; 

Con tal uso:

for(AUTO it = points.begin(); it != points.end(); ++it) 
{ 
    ... 
} 

Pero, T1 y T2 son diferentes. Cómo mover información sobre T1 a operador T2()? ¿Es realmente posible?

Respuesta

12

Si una extensión de biblioteca fuera fácilmente implementable, no habría habido necesidad de una extensión de idioma. Consulte N1607 para obtener detalles sobre la propuesta automática.

Sin embargo, el article en el Boost.Foreach (que hace lo que usted quiere) la macro puede ayudar a entender los problemas relacionados con dicha implementación.

¿Qué es BOOST_FOREACH?

En C++, escribir un ciclo que itera sobre una secuencia es tedioso. Podemos o bien utilizar iteradores, lo que requiere una cantidad considerable de caldera de la placa, o podemos usar el std :: for_each() algoritmo y mover nuestro cuerpo bucle en un predicado, lo que requiere no menos caldera de la placa y nos obliga a mover nuestra lógica lejos de donde será utilizada. En cambio, algunos otros lenguajes, como Perl, proporcionan una construcción dedicada "foreach" que automatiza este proceso. BOOST_FOREACH es solo tal construcción para C++. Itera sobre secuencias para nosotros, liberándonos de teniendo que tratar directamente con los iteradores o escribir predicados.

BOOST_FOREACH está diseñado para facilidad de uso y eficiencia. No realiza asignaciones dinámicas , no realiza llamadas o llamadas de función virtuales a través de punteros de función , y no realiza llamadas que no son transparentes para el optimizador del compilador . Esto da como resultado generación de código casi óptima; el rendimiento de BOOST_FOREACH es generalmente dentro de un pequeño porcentaje del lazo codificado a mano equivalente. Y aunque BOOST_FOREACH es una macro, es notablemente buena. Es evalúa sus argumentos exactamente una vez, sin sorpresas desagradables.

+0

Pienso en la implementación solo para usar en for for foreach. La palabra clave auto de C++ 0x tiene muchos usos ... Gracias por el enlace, lo leeré. – k06a

+4

@ k06a: Existe una fuerte oposición en C++ para implementar algo como una nueva característica de idioma cuando se puede implementar en una biblioteca. Entonces, si algo termina en el lenguaje propiamente dicho, puede estar bastante seguro de que nadie ha encontrado la forma de hacerlo correctamente en una biblioteca. (Por ejemplo, lo que 'std :: function' y' std :: bind' do está incorporado en el lenguaje en muchos otros lenguajes, pero es una función de biblioteca en C++.) – sbi

+1

Siempre me he preguntado por qué BOOST_FOREACH es un pequeño porcentaje lejos de un bucle "codificado a mano". –

10

Hay una macro BOOST_AUTO que más o menos hace lo que la palabra clave auto ... Sin embargo, una mirada a su implementación le dirá que es mucho mejor encontrar una manera de utilizar C++ 0x:>

+0

Gracias por el enlace. Lectura ... – k06a

+0

Además, si el compilador no es compatible con decltype o typeof, BOOST_AUTO solo podrá manejar los tipos incorporados, así como muchos tipos de biblioteca estándar. Otros tipos definidos por el usuario tienen que estar "registrados" para que BOOST_AUTO los reconozca, si no recuerdo mal. – sellibitze

2

El problema más inmediato es obtener información del tipo deducido a una declaración de miembro de datos.

class AUTO 
{ 
public: 
    template <typename T1> 
    AUTO(T1); 

    T1 state; // eg deque<...>::iterator - need this! 
}; 

que claramente no va a pasar porque el objeto AUTO debe asignarse antes de la función se llama.

Dado typeof o decltype, no es tan difícil, sin embargo.

#define AUTO(name, initializer) typeof(initializer) name = initializer 

Por supuesto, esto tiene muchas restricciones. Y typeof no es estándar. Con el soporte de múltiples compiladores, esta sería probablemente la base para esas herramientas de Boost.

3

Puede utilizar estas macros para solucionar este problema de forma estándar.

#define DEF_DED(D, E) any_base const & D = make_any_concrete((E)) 
#define DED(D, E) get_t(D, true ? ded_ty() : get_idt((E))) 

template<typename T> struct id { 
    typedef T type; 
}; 

template<typename T> 
id<T> get_idt(T t) { return id<T>(); } 

struct any_base { }; 

template<typename D> 
struct any_concrete : any_base { 
    any_concrete(D d):d(d) {} 
    mutable D d; 
}; 

template<typename T> 
any_concrete<T> make_any_concrete(T x) { return any_concrete<T>(x); } 

struct ded_ty { 
    template<typename T> 
    operator id<T>() { return id<T>(); } 
}; 

template<typename T> 
T &get_t(any_base const &b, id<T>) { return static_cast<any_concrete<T> const&>(b).d; } 

Así que su ciclo for se convierte en

for(DEF_DED(it, points.begin()); 
    DED(it, points.begin()) != points.end(); 
    ++DED(it, points.begin())) 
{ 
    ... 
} 

crédito va a Conditional Love: FOREACH Redux, por Eric Niebler. Sin embargo, no estoy seguro de si realmente vale la pena :)