// Otro ejercicio para entender un poco más de C++ actual, como // supermercado.cc. // Esto es la primera vez que usé for con ranges, unordered_map, // std::numeric_limits, make_pair (lo cual, creo que es obsoleto), e // inicialización de miembros estáticos con el constructor default. #include #include #include #include #include #include // para no usar std::numeric_limits::infinity() using std::cout, std::string, std::ostream, std::pair; class MonedasIncomparables : public std::exception { const char *what() const noexcept override { return "Monedas incomparables"; } }; class TipoDeCambio { bool conocido; double cotización; public: TipoDeCambio() {} TipoDeCambio(double c) : conocido(true), cotización(c) {} bool se_sabe() const { return conocido; } double convertir(double cantidad) const { return cantidad * cotización; } TipoDeCambio inverso() const { return TipoDeCambio(1/cotización); } }; class Precio { enum { PESOS, DOLARES } moneda; double tamaño; friend ostream& operator<<(ostream& out, const Precio& p) { if (p.moneda == PESOS) { return out << "AR$" << p.tamaño; } else { return out << "US$" << p.tamaño; } } Precio() {} public: static TipoDeCambio dolar_blue; Precio(double f) : moneda(PESOS), tamaño(f) {} static Precio dolares(double f) { Precio p = f; p.moneda = DOLARES; return p; } bool operator<(const Precio b) const { if (moneda == b.moneda) return tamaño < b.tamaño; if (!dolar_blue.se_sabe()) throw MonedasIncomparables(); if (moneda == PESOS) return tamaño < dolar_blue.convertir(b.tamaño); return tamaño < dolar_blue.inverso().convertir(b.tamaño); } }; // Definir el valor inicial de dolar_blue TipoDeCambio Precio::dolar_blue; class Hiperfracaso : public std::exception { protected: string qué; public: Hiperfracaso(const string& qué_) : qué(qué_) {} const char *what() const noexcept override { return qué.c_str(); } }; class NoSeEncuentra : public Hiperfracaso { public: NoSeEncuentra(const string& qué_) : Hiperfracaso("No se encuentra: " + qué_) { } }; class YaSeEncuentra : public Hiperfracaso { public: YaSeEncuentra(const string& qué_) : Hiperfracaso("Ya se encuentra: " + qué_) { } }; class Hipermercado { // Pensé en usar priority_queue, pero esto me parecía menos // complicado: typedef std::unordered_map proveedores; std::unordered_map productos; public: void agregar_proveedor(const string& producto, const string& proveedor, Precio precio); void editar_precio(const string& producto, const string& proveedor, Precio precio); auto mejor_proveedor(const string& producto) const; }; auto Hipermercado::mejor_proveedor(const string& producto) const { auto p = productos.find(producto); if (p == productos.end()) throw NoSeEncuentra(producto); pair mejor("No existe", HUGE_VAL); for (auto& q : p->second) { if (q.second < mejor.second) mejor = q; } return mejor; } void Hipermercado::agregar_proveedor(const string& producto, const string& proveedor, Precio precio) { auto p = productos.find(producto); if (p == productos.end()) { productos[producto] = proveedores(); } // Me costó debuguear por qué no me aparecían los productos sin este // &. auto& q = productos.at(producto); auto r = q.find(proveedor); if (r != q.end()) throw YaSeEncuentra(producto + " de " + proveedor); q.emplace(std::make_pair(proveedor, precio)); } void Hipermercado::editar_precio(const string& producto, const string& proveedor, Precio precio) { auto p = productos.find(producto); if (p == productos.end()) throw NoSeEncuentra(producto); auto& q = p->second; // probablemente mejor que .at() auto r = q.find(proveedor); if (r == q.end()) throw NoSeEncuentra(producto + " de " + proveedor); r->second = precio; } int main() { Hipermercado m; try { m.agregar_proveedor("Bananas", "Dole", 2499.99); m.agregar_proveedor("Bondiola", "San Francisco", 5499.99); m.agregar_proveedor("Bondiola", "Res", 3999.99); auto bananas = m.mejor_proveedor("Bananas"); cout << "Mejor bananas son de " << bananas.first << " al precio " << bananas.second << "\n"; auto bondiola = m.mejor_proveedor("Bondiola"); cout << "Mejor bondiola es de " << bondiola.first << " al precio " << bondiola.second << "\n"; m.editar_precio("Bondiola", "San Francisco", 3299.99); cout << "San Francisco cortó el precio!\n"; auto bondiola2 = m.mejor_proveedor("Bondiola"); cout << "Mejor bondiola es de " << bondiola2.first << " al precio " << bondiola2.second << " ahora!\n"; auto precio = Precio::dolares(1.49); cout << "Agregando Chiquita a " << precio << "\n"; m.agregar_proveedor("Bananas", "Chiquita", precio); Precio::dolar_blue = 1285.0; // cout << "Nuestro " << precio << " es menor que $2500? " << // (precio < 2500) << "\n"; // cout << "Y $2500 es menor que " << "precio? " << // (Precio(2500) < precio) << "\n"; auto bananas2 = m.mejor_proveedor("Bananas"); cout << "Ahora el mejor proveedor de bananas es de " << bananas2.first << " al precio " << bananas2.second << "\n"; } catch (const std::exception& e) { std::cerr << "Sorpresa: " << e.what() << std::endl; return 1; } return 0; }