In questo codice di esempio, il ciclo all'interno delle due funzioni process()
è duplicato. L'unica differenza è che uno è const
e l'altro no.Come riutilizzare il codice tra le funzioni const e non-const che chiamano altre funzioni
C'è un modo per rimuovere la duplicazione del codice, in modo che il ciclo esista solo una volta? Questo è solo un esempio, ma nel codice reale il ciclo è piuttosto complesso, quindi per motivi di manutenzione voglio solo che il ciclo esista una sola volta.
#include <iostream>
#include <vector>
typedef unsigned int Item;
typedef std::vector<Item *> Data;
struct ReadOnlyAction {
void action(const Item *i)
{
// Read item, do not modify
std::cout << "Reading item " << *i << "\n";
}
};
struct ModifyAction {
void action(Item *i)
{
// Modify item
std::cout << "Modifying item " << *i << "\n";
(*i)++;
}
};
void process(Data *d, ModifyAction *cb) {
// This loop is actually really complicated, and there are nested loops
// inside it three levels deep, so it should only exist once
for (Data::iterator i = d->begin(); i != d->end(); i++) {
Item *item = *i;
cb->action(item);
}
}
void process(const Data *d, ReadOnlyAction *cb) {
// This is the same loop as above, and so the code should not be duplicated
for (Data::const_iterator i = d->begin(); i != d->end(); i++) {
const Item *item = *i;
cb->action(item);
}
}
void incrementData(Data *d) {
// Here we modify the pointer, and need to loop through it
ModifyAction incrementItem;
process(d, &incrementItem);
}
void saveData(const Data *d) {
// Here we aren't allowed to modify the pointer, but we still need
// to loop through it
ReadOnlyAction printItem;
process(d, &printItem);
}
int main(void)
{
Data d;
// Populate with dummy data for example purposes
unsigned int a = 123;
unsigned int b = 456;
d.push_back(&a);
d.push_back(&b);
incrementData(&d);
saveData(&d);
return 0;
}
Si prega di essere consapevoli del fatto che questa non è una domanda duplicata. Le seguenti domande e risposte simili sono diverse:
- 123758 - copre solo semplici funzioni che restituiscono valori, che tale funzione chiama altre funzioni in modo che le soluzioni indicate non non funzionano per questo problema
- 23809745 - stesso problema, copre solo semplici funzioni che restituiscono valori, le risposte non funzionano per questo problema
Se tento la soluzione data a queste risposte, non funziona, ma si presenta così:
template <class CB>
void processT(const Data *d, CB *cb) {
// Single loop in only one location
for (Data::const_iterator i = d->begin(); i != d->end(); i++) {
const Item *item = *i;
// Compilation fails on the next line, because const Item* cannot be
// be converted to Item* for the call to ModifyAction::action()
cb->action(item);
}
}
void process(const Data *d, ReadOnlyAction *cb) {
processT(d, cb);
}
void process(Data *d, ModifyAction *cb) {
processT(static_cast<const Data *>(d), cb);
}
Questo è un esempio semplificato, in modo che sarebbe molto apprezzato se risposte potrebbero concentrarsi sul problema (come rimuovere il ciclo duplicato dall'interno delle due process()
funzioni) piuttosto che i commenti circa la progettazione - modifiche al design vanno bene ovviamente se rimuove il ciclo duplicato nel processo.
si può non solo fare la parte data' 'della firma nel modello, in modo che la proprietà const si propaga da la funzione? – Soren
Perché non specificare il tipo iteratore come uno dei parametri del modello o passare gli iteratori come parametri alla funzione? –
perché una versione che utilizza const e una no? Quale esigenza di progettazione sta guidando la necessità di due versioni dello stesso ciclo? –