Ha C ++ hanno “con” parola chiave come Pascal?
-
21-09-2019 - |
Domanda
with
parola chiave in Pascal può essere utilizzato per un rapido accesso al campo di un record.
Qualcuno sa se C ++ ha qualcosa di simile a questo?
Ex: Ho un puntatore con molti campi e io non voglio scrivere in questo modo:
if (pointer->field1) && (pointer->field2) && ... (pointer->fieldn)
quello che voglio veramente è qualcosa di simile in C ++:
with (pointer)
{
if (field1) && (field2) && .......(fieldn)
}
Soluzione
In C ++, è possibile inserire il codice in un metodo di riferimento di classe essere da pointer
. C'è possibile fare riferimento direttamente i membri senza utilizzare il puntatore. Ne fanno inline
ed è praticamente ottenere quello che vuoi.
Altri suggerimenti
Probabilmente il più vicino si può ottenere è questo: (Per favore non mi downvote, questo è solo un esercizio accademico Naturalmente, non è possibile utilizzare tutte le variabili locali nel corpo di questi blocchi with
artificiali.!)
struct Bar {
int field;
};
void foo( Bar &b ) {
struct withbar : Bar { void operator()() {
cerr << field << endl;
}}; static_cast<withbar&>(b)();
}
In alternativa, un po 'più demoniaco,
#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 in 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;
non v'è alcuna parola chiave.
Mi piace usare:
#define BEGIN_WITH(x) { \
auto &_ = x;
#define END_WITH() }
Esempio:
BEGIN_WITH(MyStructABC)
_.a = 1;
_.b = 2;
_.c = 3;
END_WITH()
Anche se programmo per lo più in Delphi che ha una parola chiave with
(dal momento che Delphi è un derivato Pascal), io non uso with
. Come altri hanno detto:. Fa risparmiare un po 'di battitura, ma la lettura è reso più difficile
In un caso come il codice qui sotto si potrebbe essere tentati di utilizzare 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;
Utilizzando with
questo assomiglia a questo
with cxGrid.DBTableView.ViewData.Records do
begin
FieldByName('foo').Value = 1;
FieldByName('bar').Value = 2;
FieldByName('baz').Value = 3;
end;
Io preferisco usare una tecnica diversa con l'introduzione di una variabile che punta in più per la stessa with
cosa sarebbe indicando a. In questo modo:
var lRecords: TDataSet;
lRecords := cxGrid.DBTableView.ViewData.Records;
lRecords.FieldByName('foo').Value = 1;
lRecords.FieldByName('bar').Value = 2;
lRecords.FieldByName('baz').Value = 3;
In questo modo non c'è ambiguità, si risparmia un po 'di battitura e l'intento del codice è più chiaro che usando with
No, C ++ non ha un tale parola chiave.
C ++ non ha una funzione simile. E molti considerano "CON" in Pascal ad essere un problema perché può rendere il codice ambiguo e difficile da leggere, ad esempio, è difficile sapere se campo1 è un membro del puntatore o una variabile locale o qualcos'altro. Pascal permette anche di più con-variabili come "Con Var1, Var2", che rende ancora più difficile.
Il più vicino si può ottenere è metodo concatenamento :
myObj->setX(x)
->setY(y)
->setZ(z)
per l'impostazione più campi e using
per i namespace.
with (OBJECT) {CODE}
Non esiste una cosa come in C ++.
È possibile inserire il codice come è in un metodo di oggetto, ma non è sempre auspicabile.
Con C ++ 11 è possibile ottenere abbastanza vicino con la creazione di alias con nome breve per oggetto.
Ad esempio di codice dato in questione apparirà in questo modo:
{
auto &_ = *pointer;
if (_.field1 && ... && _.fieldn) {...}
}
(Le parentesi graffe circostanti sono utilizzati per limitare la visibilità di alias _
)
Se si usa un po 'di campo molto spesso è possibile alias direttamente:
auto &field = pointer->field;
// Even shorter alias:
auto &_ = pointer->busy_field;
In primo luogo ho sentito che qualcuno non piace 'con'. Le regole sono perfettamente semplice, non è diverso da ciò che accade all'interno di una classe in C ++ o Java. E non dimenticare che è possibile attivare una significativa ottimizzazione del compilatore.
Dopo aver scritto numerosi parser, questa sembra una lista morto semplice sguardo per l'oggetto di nome, statici o dinamici. Inoltre, non ho mai visto una situazione in cui il compilatore non ha identificato correttamente l'oggetto e il tipo mancante, quindi tutte quelle scuse per non consentire a con ... costruzione ENDWITH sembrerebbe essere un sacco di sciocchezze. Per il resto di noi inclini a nomi lungo oggetto soluzione è creare definisce semplici. non ha potuto resistere, supponiamo di avere:
#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;
Il seguente approccio si basa su Boost. Se il compilatore supporta auto
del C ++ 0x, allora è possibile utilizzare tale e sbarazzarsi della dipendenza Boost.
responsabilità : si prega di non farlo in qualsiasi codice che deve essere mantenuto o letto da qualcun altro (o anche da soli in pochi mesi):
#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");
}
}
Posso vedere un caso in cui 'con' è effettivamente utile.
Nel metodi per strutture di dati ricorsive, si ha spesso il 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);
}
}
errori causati da errori di battitura come questo sono molto difficili da trovare.
Con 'con' si potrebbe scrivere
void A::method()
{
for (A* node = this; node; node = node->next) with (node) {
abc(value1);
def(value2);
xyz(value3);
}
}
Questo probabilmente non siano superiori tutti gli altri aspetti negativi menzionati per 'con', ma altrettanto un info interessante ...
Forse è possibile:
auto p = *pointer;
if (p.field1) && (p.field2) && ... (p.fieldn)
O creare un piccolo programma che capirà le dichiarazioni with
in C ++ e tradurli ad una qualche forma di una valida C ++.
No, non v'è alcuna parola chiave with
in C / C ++.
Ma è possibile aggiungere con un po 'di codice preprocessore:
/* Copyright (C) 2018 Piotr Henryk Dabrowski, Creative Commons CC-BY 3.0 */
#define __M2(zero, a1, a2, macro, ...) macro
#define __with2(object, as) \
for (typeof(object) &as = (object), *__i = 0; __i < (void*)1; ++__i)
#define __with1(object) __with2(object, it)
#define with(...) \
__M2(0, ##__VA_ARGS__, __with2(__VA_ARGS__), __with1(__VA_ARGS__))
Utilizzo:
with (someVeryLongObjectNameOrGetterResultOrWhatever) {
if (it)
it->...
...
}
with (someVeryLongObjectNameOrGetterResultOrWhatever, myObject) {
if (myObject)
myObject->...
...
}
semplificati definizioni unoverloaded (sceglierne una):
senza nome (Kotlin stile it
):
#define with(object) \
for (typeof(object) &it = (object), *__i = 0; __i < (void*)1; ++__i)
denominato:
#define with(object, as) \
for (typeof(object) &as = (object), *__i = 0; __i < (void*)1; ++__i)
Naturalmente il ciclo for
ha sempre una sola passata e verrà ottimizzato dal compilatore.
#include <iostream>
using namespace std;
template <typename T>
struct with_iter {
with_iter( T &val ) : p(&val) {}
inline T* begin() { return p; }
inline T* end() { return p+1; }
T *p;
};
#define with( N, I ) for( auto &N : with_iter<decltype(I)>(I) )
int main() {
with( out , cout ) {
out << "Hello world!" << endl;
}
return 0;
}
Nuf ha detto ...
Un modo semplice per farlo è la seguente
class MyClass
{
int& m_x;
public MyClass(int& x)
{
m_x = x;
m_x++;
}
~MyClass()
{
m_x--;
}
}
int main():
{
x = 0;
{
MyClass(x) // x == 1 whilst in this scope
}
}
Ho scritto python tutto il giorno e appena demolito questo giù prima che qualcuno mi prende per la pulizia. In un programma più ampio questo è un esempio di come mantenere un conteggio affidabile per qualcosa.