Domanda Risolto Scrivere in modo efficiente una funzione che ritorni stringhe multiple

Stato
Discussione chiusa ad ulteriori risposte.

DanyDollaro

Utente Electrum
14 Luglio 2018
148
41
58
138
Ultima modifica:
Salve, come dal titolo volevo sapere quali sono alcuni dei metodi migliori per strutturare una funzione in modo che possa ritornare più di una stringa, la funzione in questione dovrebbe ricevere come parametro un valore di tipo intero che possa essere associato a delle stringhe, ne ho scritta una molto basilare:
C++:
#include <iostream>

enum food
{
    hamburger    = 1,
    chips        = 2
};

enum drinks
{
    water    = 4,
    soda     = 8
};

// Essendo una versione semplificata è voluta la mancanza dei controlli sulle dimensioni del buffer
// d'altronde si prospetta che quest'ultimo sia sufficientemente capiente
bool GetOrderAsString(int Order, char* IpBuffer)
{
    int streamPos = 0;
    std::string product;
    bool write = true;

    // Ottieni l'oggetto di tipo "food"
    switch (Order & 0x03)
    {
    case hamburger:
        product = "hamburger";
        break;

    case chips:
        product = "chips";
        break;
    }

    // Scrivi l'ordinazione nel buffer
    streamPos = product.length();
    memcpy(IpBuffer, product.data(), product.length());

    // Ottieni l'oggetto di tipo "drink", potrebbe anche non essere preso
    switch (Order & 0x0C)
    {
    case water:
        product = "water";
        break;

    case soda:
        product = "soda";
        break;

    default:
        write = false;
        break;
    }

    if (write)
    {
        // Aggiungi un carattere separatore
        IpBuffer[streamPos++] = '|';

        // Scrivi la seconda ordinazione nel buffer
        memcpy(IpBuffer + streamPos, product.data(), product.length());
    }

    return true;
}

int main()
{
    int Order_1 = hamburger;
    int Order_2 = chips | water;

    char buffer_1[32] = { 0 };
    char buffer_2[32] = { 0 };

    // Converti gli ordini nelle variabili "int" nelle corrispettive stringhe
    GetOrderAsString(Order_1, buffer_1);
    GetOrderAsString(Order_2, buffer_2);

    std::cout << "Order_1: " << buffer_1 << std::endl << "Order_2: " << buffer_2;

    getchar();
    return 0;
}
l'output mostrato su console è il seguente:
Codice:
Order_1: hamburger
Order_2: chips|water
Dopo averla finita di scrivere mi sono venute altre idee in mente, tra cui:
1) Definire una classe contenete delle stringhe o dei puntatori su di esse ed usarla come valore di ritorno, ma il suo concepimento ed impiego sarebbe risultato al quanto forzato dato che verrebbe utilizzata solo come valore di ritorno di quell'apposita funzione.
2) Dichiarare delle variabili globali di tipo stringa e strutturare la funzione in modo che il suo valore di ritorno sia un vettore di puntatori sulle corrispettive, oppure dichiarale come statiche costanti all'interno della funzione ma non ho idea se possa essere ritenuto come un qualcosa di fatto bene.
3) Nel caso i valori interi associabili a delle stringhe siano pochi si potrebbero definire delle mappe di questo tipo std::map<int, char*> ed associare a ogni valore di int tutte le corrispettive stringhe in una sola char*, ad ogni modo risulterebbe simile alla soluzione numero 2.

Dunque mi piacerebbe conoscere i vostri pareri sull'argomento.
 
Appena ho letto il testo ho subito pensato a std::map, e' la soluzione piu' flessibile, non solo perche' puoi cambiare la lista agilmente a runtime, ma perche' puoi inizializzarla in modo comprensibile come variabile globale:

C++:
static std::map<int, std::string> Products = {
    { 1, "Hamburger" },
    { 2, "Chips" }
};

// Variante con mappa constante + enum
enum class food
{
    hamburger = 1,
    chips = 2
};

const std::map<food, std::string> Products = {
    { food::hamburger, "Hamburger" },
    { food::chips, "Chips" }
};

Puoi mettere la mappa come static o come const (e con chiave come int o come food), dipende se hai intenzione di modificarla a runtime.
In base a questo dalla tua funzione puoi o tornare una const char* (se anche la mappa e' const) se no o cloni la stringa e la ritorni in una std::string o la setti con memcpy come nel tuo esempio.
 
  • Mi piace
Reazioni: DanyDollaro
Grazie per la risposta :D, in più come descritto nel punto numero 2 vorrei sapere se definire delle variabili locali statiche per essere successivamente usate come valori di ritorno possa essere ritenuta come buona pratica, come mostrato nel seguente codice:
C++:
#include <iostream>

const char* GetFood(int Selection)
{
    static const char* hamburger = "hamburger";
    static const char* chips = "chips";

    switch (Selection)
    {
    case 1:
        return hamburger;
        break;

    case 2:
        return chips;
        break;

    default:
        return nullptr;
        break;
    }
}

int main()
{
    std::cout << GetFood(1);

    getchar();
    return 0;
}
 
In quest'ultimo caso static e' superfluo essendo gia' una const che di default lo e' implicitamente. Non e' una buona pratica ma finche' lo switch e' corto e' accettabile. Lo svantaggio di questo e' che non hai modi facili per printare/scorrere tutte le possibilita' tramite un ciclo ad esempio. Usando una std::map puoi printare una tabella di traduzione in due righe e fare tanto altro:

C++:
    // Inserimento nuovo prodotto
    Products.insert(std::pair<int, std::string>(3, "Sandwich"));
    // Print di tutti gli elementi
    for (const auto& product : Products)
        std::cout << "ID: " << product.first << " - Testo: " << product.second << std::endl;
 
  • Mi piace
Reazioni: DanyDollaro
Stato
Discussione chiusa ad ulteriori risposte.