2010-02-17 27 views
12

with palabra clave en Pascal se puede utilizar para acceder rápidamente al campo de un registro. ¿Alguien sabe si C++ tiene algo similar a eso?¿Tiene C++ una palabra clave "con" como Pascal?

Ex: que tiene un puntero con muchos campos y que no quiero escribir así:

if (pointer->field1) && (pointer->field2) && ... (pointer->fieldn) 

lo que realmente quiero es algo como esto en C++:

with (pointer) 
{ 
    if (field1) && (field2) && .......(fieldn) 
} 
+0

Huh. Javascript tiene la palabra clave 'with' y hace sustancialmente lo mismo; No me di cuenta de que tenía un pedigrí que se remontaba a Pascal (!). –

+0

Tal vez proviene de Cobol o ADA, quién sabe ... –

+0

Hay un en en Ada, pero no con ese significado. – AProgrammer

Respuesta

11

En C++, puede poner el código en un método de la clase que se está consultando por pointer. Allí puede hacer referencia directamente a los miembros sin usar el puntero. Hazlo inline y obtienes lo que quieres.

+0

¿Qué quiere decir con "make it inline'"? ¿Puedes declarar el método solo dentro de otra función? Es extraño ... – Dacav

+0

@Dacav Esta respuesta solo sugiere sumar un método a la clase utilizada por 'with'. Estar 'en línea' le permite entrar en un encabezado, pero de lo contrario, eso es una pista falsa. Tal método debe declararse en su clase original y definido fuera de cualquier otra función. Mi respuesta a continuación tiene una solución a ambos problemas. – Potatoswatter

10

no, no hay tal palabra clave.

5

No, C++ no tiene ninguna palabra clave.

5

C++ no tiene una función como esa. Y muchos consideran que "CON" en Pascal es un problema porque puede hacer que el código sea ambiguo y difícil de leer, por ejemplo, es difícil saber si el campo1 es un miembro del puntero o una variable local u otra cosa. Pascal también permite múltiples variables con, como "Con Var1, Var2", lo que lo hace aún más difícil.

+4

Siempre existe la pregunta de que si algo se puede abusar, significa que es malo. –

+3

Claro, porque la búsqueda de nombre en C++ es * tan directa *. No -1, pero creo que el argumento "puede hacer que el código sea ambiguo" no se cumple cuando se considera el caso de búsqueda dependiente de argumentos para funciones, especialmente para instancias de plantillas de funciones. –

+0

Estoy de acuerdo en que puede ser útil, pero lo he visto abusado tantas veces que me mantengo alejado de su uso. En particular, puede morderle si se cambia el nombre de field1 en el registro, de modo que su código con -y ahora de forma silenciosa se refiere a otra variable en el alcance con el mismo nombre. En lugar de utilizar uno de los otros enfoques sugeridos aquí: use una variable local con nombre corto o muévala a una función/método. –

16

Probablemente lo más cercano que puede obtener es esto: (Por favor, no me baje, esto es solo un ejercicio académico. ¡Por supuesto, no puede usar ninguna variable local en el cuerpo de estos bloques artificiales with!)

struct Bar { 
    int field; 
}; 

void foo(Bar &b) { 
    struct withbar : Bar { void operator()() { 
     cerr << field << endl; 
    }}; static_cast<withbar&>(b)(); 
} 

o bien, un poco más por el demonio,

#define WITH(T) do { struct WITH : T { void operator()() { 
#define ENDWITH(X) }}; static_cast<WITH&>((X))(); } while(0) 

struct Bar { 
    int field; 
}; 

void foo(Bar &b) { 
    if (1+1 == 2) 
     WITH(Bar) 
      cerr << field << endl; 
     ENDWITH(b); 
} 

o en C++ 0x

#define WITH(X) do { auto P = &X; \ 
struct WITH : typename decay< decltype(X) >::type { void operator()() { 
#define ENDWITH }}; static_cast<WITH&>((*P))(); } while(0) 

     WITH(b) 
      cerr << field << endl; 
     ENDWITH; 
+4

¡Un enfoque interesante! :) –

+0

Muy bueno :). Sin embargo, me gustaría mencionar que para los pocos de nosotros que trabajamos con el compilador de Metrowerks, es muy probable que esto no funcione (no funciona bien con las estructuras en una función) – arke

+0

@arke: ¿en serio? Eso es sorprendente, me encantó Metrowerks cuando era el estándar Mac. Hmm, parece que perdieron a Howard Hinnant ... – Potatoswatter

8

Aunque programo principalmente en Delphi que tiene una palabra clave with (ya que Delphi es un derivado de Pascal), no utilizo with. Como han dicho otros: ahorra un poco de tipeo, pero la lectura se hace más difícil.

En un caso como el código de abajo puede ser tentador utilizar with:

cxGrid.DBTableView.ViewData.Records.FieldByName('foo').Value = 1; 
cxGrid.DBTableView.ViewData.Records.FieldByName('bar').Value = 2; 
cxGrid.DBTableView.ViewData.Records.FieldByName('baz').Value = 3; 

Usando with esto se parece a esto

with cxGrid.DBTableView.ViewData.Records do 
begin 
    FieldByName('foo').Value = 1; 
    FieldByName('bar').Value = 2; 
    FieldByName('baz').Value = 3; 
end; 

yo prefiero usar una técnica diferente mediante la introducción de un extra variable apuntando a lo mismo with apuntando hacia. De esta manera:

var lRecords: TDataSet; 

lRecords := cxGrid.DBTableView.ViewData.Records; 

lRecords.FieldByName('foo').Value = 1; 
lRecords.FieldByName('bar').Value = 2; 
lRecords.FieldByName('baz').Value = 3; 

De esta manera no hay ninguna ambigüedad, se ahorra un poco en escribir y la intención del código es más claro que el uso de with

+3

Esta estrategia también funciona con C++, usando una variable local 'T &' o 'T const &' para mantener una referencia a la expresión larga (que debe ser un valor l apropiado en el caso 'T &'). Para que se destaque visualmente, generalmente elijo la variable '_'. –

0

El siguiente método se basa en Boost. Si su compilador es compatible con auto de C++ 0x, puede usarlo y deshacerse de la dependencia de Boost.

Negación: por favor no hacer esto en cualquier código que se debe mantener o leído por otra persona (o incluso por sí mismo dentro de unos meses):

#define WITH(src_var)            \ 
    if(int cnt_ = 1)            \ 
     for(BOOST_AUTO(const & _, src_var); cnt_; --cnt_) 


int main() 
{ 
    std::string str = "foo"; 

    // Multiple statement block 
    WITH(str) 
    { 
     int i = _.length(); 
     std::cout << i << "\n"; 
    } 

    // Single statement block 
    WITH(str) 
     std::cout << _ << "\n"; 

    // Nesting 
    WITH(str) 
    { 
     std::string another("bar"); 
     WITH(another) 
      assert(_ == "bar"); 
    } 
} 
1

primera vez que escucho que a nadie le gusta 'con'. Las reglas son perfectamente sencillas, no diferentes de lo que sucede dentro de una clase en C++ o Java. Y no olvide que puede desencadenar una optimización significativa del compilador.

3

Lo más cerca que se puede conseguir es method chaining:

myObj->setX(x) 
    ->setY(y) 
    ->setZ(z) 

para configurar múltiples campos y using de espacios de nombres.

0

Puedo ver una instancia donde 'con' es realmente útil.

en métodos para estructuras de datos recursivas, que a menudo tienen el caso:

void A::method() 
{ 
    for (A* node = this; node; node = node->next) { 
    abc(node->value1); 
    def(value2); // -- oops should have been node->value2 
    xyz(node->value3); 
    } 
} 

errores causados ​​por errores tipográficos de este tipo son muy difíciles de encontrar.

Con 'con' podría escribir

void A::method() 
{ 
    for (A* node = this; node; node = node->next) with (node) { 
    abc(value1); 
    def(value2); 
    xyz(value3); 
    } 
} 

Esto probablemente no outweight todos los otros aspectos negativos mencionados para 'con', pero sólo como una información interesante ...

0

Tal vez usted pueda :

auto p = *pointer; 
if (p.field1) && (p.field2) && ... (p.fieldn) 

O crear un pequeño programa que va a entender with declaraciones en C++ y traducirlos a alguna forma de C++ válida.

+0

Probablemente debería ser 'auto & p = * puntero', ya que su código toma una copia. –

1

Después de haber escrito numerosos analizadores sintácticos, esto parece una búsqueda simple y sin importancia para el objeto nombrado, ya sea estático o dinámico. Además, nunca he visto una situación en la que el compilador no identificara correctamente el objeto y el tipo que faltaba, por lo que todas esas excusas poco convincentes para no permitir una construcción CON ... ENDWITH parecerían ser un montón de tonterías. Para el resto de nosotros propensos a nombres de objetos largos, una solución es crear definiciones simples. No se pudo resistir, supongamos que tengo:

#include<something> 
    typedef int headache; 
    class grits{ 
     public: 
     void corn(void); 
     void cattle(void); 
     void hay(void);}; //insert function defs here 
    void grits::grits(void)(printf("Welcome to Farm-o-mania 2012\n");}; 

    #define m mylittlepiggy_from_under_the_backporch. 
    headache main(){ 
     grits mylittlepiggy_from_under_the_backporch; 
     m corn(); //works in GCC 
     m cattle(); 
     m hay(); 
     return headache; 
1
with (OBJECT) {CODE} 

No existe tal cosa en C++.
Puede poner CÓDIGO como está en un método de OBJETO, pero no siempre es deseable.

Con C++ 11 puedes acercarte creando alias con un nombre corto para OBJECT.
Por ejemplo código dado en cuestión que se verá así:

{ 
    auto &_ = *pointer; 
    if (_.field1 && ... && _.fieldn) {...} 
} 

(Las llaves de los alrededores se utilizan para limitar la visibilidad de alias _)

Si utiliza algún campo muy a menudo se puede crear un alias que directamente:

auto &field = pointer->field; 
// Even shorter alias: 
auto &_ = pointer->busy_field; 
7

me gusta usar:

#define BEGIN_WITH(x) { \ 
     auto &_ = x; 

    #define END_WITH() } 

Ejemplo:

BEGIN_WITH(MyStructABC) 
    _.a = 1; 
    _.b = 2; 
    _.c = 3; 
    END_WITH() 
Cuestiones relacionadas