Cos'è un Namespace?

Un namespace è un contenitore che raggruppa identificatori (funzioni, classi, variabili) per evitare conflitti di nomi. È come una "cartella" per il tuo codice.

C++Namespace — definizione e uso
#include <iostream>
using namespace std;

// Dichiarazione namespace
namespace geometria {
    const double PI = 3.14159265358979;

    double area_cerchio(double r) { return PI * r * r; }
    double perimetro_cerchio(double r) { return 2 * PI * r; }

    struct Punto {
        double x, y;
        double distanza(const Punto &altro) const {
            double dx=x-altro.x, dy=y-altro.y;
            return sqrt(dx*dx+dy*dy);
        }
    };

    // Namespace annidato
    namespace forme3d {
        double volume_sfera(double r)   { return (4.0/3.0) * PI * r * r * r; }
        double volume_cilindro(double r, double h) { return PI * r * r * h; }
    }
}

// I namespace possono essere "aperti" più volte
namespace geometria {
    double area_triangolo(double b, double h) { return 0.5 * b * h; }
}

int main() {
    // Accesso qualificato
    cout << geometria::area_cerchio(5.0) << "\n";
    cout << geometria::PI << "\n";

    // Accesso namespace annidato
    cout << geometria::forme3d::volume_sfera(3.0) << "\n";

    // using declaration: porta UNO specifico nome
    using geometria::Punto;
    Punto p1{0, 0}, p2{3, 4};
    cout << "Distanza: " << p1.distanza(p2) << "\n";

    // using directive: porta TUTTO il namespace (sconsigliato nei header!)
    // using namespace geometria;
    // area_cerchio(5.0);  // OK dopo using namespace

    // Alias di namespace
    namespace geo3d = geometria::forme3d;
    cout << "Volume cilindro: " << geo3d::volume_cilindro(2, 5) << "\n";

    return 0;
}

Anonymous Namespace e Inline Namespace

C++Namespace anonimo e inline namespace
#include <iostream>
using namespace std;

// Namespace anonimo: visibile SOLO in questo file
// Equivale a "static" in C — evita conflitti tra file diversi
namespace {
    int helper_privato(int x) { return x * x; }
    const int COSTANTE_LOCALE = 42;
}

// Inline namespace: per versioning di API
namespace libreria {
    inline namespace v2 {  // Versione corrente (default)
        void funzione() { cout << "libreria::v2::funzione\n"; }
        int nuova_api() { return 42; }
    }
    namespace v1 {  // Versione vecchia (accesso esplicito)
        void funzione() { cout << "libreria::v1::funzione (obsoleta)\n"; }
    }
}

int main() {
    // Il namespace anonimo è accessibile nel file corrente
    cout << helper_privato(5) << "\n";       // 25
    cout << COSTANTE_LOCALE << "\n";          // 42

    // Inline namespace: accesso senza qualifica (usa v2)
    libreria::funzione();          // chiama v2
    libreria::v1::funzione();      // chiama v1
    libreria::v2::funzione();      // chiama v2 esplicito
    cout << libreria::nuova_api() << "\n";   // 42

    return 0;
}

ADL — Argument-Dependent Lookup

L'ADL (o Koenig lookup) è una regola del C++ per cui il compilatore cerca automaticamente le funzioni anche nei namespace degli argomenti. Permette di scrivere cout << x invece di std::operator<<(cout, x).

C++ADL in pratica
#include <iostream>
using namespace std;

namespace fisica {
    struct Vettore { double x, y, z; };

    // Operator definito nello stesso namespace di Vettore
    Vettore operator+(const Vettore &a, const Vettore &b) {
        return {a.x+b.x, a.y+b.y, a.z+b.z};
    }

    ostream &operator<<(ostream &os, const Vettore &v) {
        return os << "(" << v.x << "," << v.y << "," << v.z << ")";
    }

    double norma(const Vettore &v) {
        return sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
    }
}

// swap personalizzato — ADL permette a std::sort, std::swap etc.
// di trovarlo automaticamente
namespace mylib {
    struct Buffer {
        int *dati; int n;
        Buffer(int n) : dati(new int[n]()), n(n) {}
        ~Buffer() { delete[] dati; }
        Buffer(Buffer &&o) noexcept : dati(o.dati), n(o.n) { o.dati=nullptr; }
    };

    // swap trovato da ADL quando si usa std::sort su mylib::Buffer
    void swap(Buffer &a, Buffer &b) noexcept {
        using std::swap;
        swap(a.dati, b.dati);
        swap(a.n,    b.n);
    }
}

int main() {
    fisica::Vettore v1{1,2,3}, v2{4,5,6};

    // ADL: il compilatore cerca operator+ in fisica:: (namespace di v1, v2)
    fisica::Vettore v3 = v1 + v2;  // Trova fisica::operator+

    // ADL: il compilatore cerca operator<< in fisica:: (namespace di v3)
    cout << v3 << "\n";  // Trova fisica::operator<<

    // ADL: cerca norma in fisica::
    cout << "norma: " << norma(v1) << "\n";  // Trova senza qualifica!

    return 0;
}

Best Practice

C++Cosa fare e cosa NON fare
// ✅ CORRETTO: usa using declaration per nomi specifici
using std::cout;
using std::string;
using std::vector;

// ✅ CORRETTO: using namespace in .cpp (mai in header)
// In file.cpp — OK
using namespace std;

// ❌ SBAGLIATO: using namespace std nei file header
// — contamina chiunque includa il tuo header
// #include "mio_header.h"  // Portato using namespace std!

// ✅ CORRETTO: struttura namespace per progetto grande
namespace myapp {
    namespace core {
        class Engine { /* ... */ };
    }
    namespace ui {
        class Window { /* ... */ };
    }
    namespace utils {
        void log(const std::string &msg);
    }
}

// ✅ CORRETTO: swap idiom
namespace mylib {
    class Widget {
        std::string nome;
        int val;
    public:
        Widget(std::string n, int v) : nome(n), val(v) {}

        // Membro swap
        void swap(Widget &other) noexcept {
            std::swap(nome, other.nome);
            std::swap(val,  other.val);
        }

        // Operatore di assegnamento con copy-and-swap idiom
        Widget &operator=(Widget other) noexcept {
            swap(other);
            return *this;
        }
    };

    // Free function swap (trovata da ADL)
    inline void swap(Widget &a, Widget &b) noexcept { a.swap(b); }
}

int main() {
    using namespace myapp;
    mylib::Widget w1{"alpha", 1}, w2{"beta", 2};
    using std::swap;
    swap(w1, w2);  // ADL trova mylib::swap
    return 0;
}
🏋️ Esercizi
1
Libreria matematica con namespace
FacileNamespace

Crea un namespace math con sotto-namespace algebra, stat e trig. In algebra: operazioni su matrici 2x2. In stat: media, varianza, deviazione standard. In trig: sin, cos, tan in gradi. Usali nel main senza using namespace.

C++
#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>

namespace math {
    const double PI = 3.14159265358979;

    namespace algebra {
        struct Mat2 { double a,b,c,d; };
        Mat2 mul(const Mat2 &x, const Mat2 &y) {
            return {x.a*y.a+x.b*y.c, x.a*y.b+x.b*y.d,
                    x.c*y.a+x.d*y.c, x.c*y.b+x.d*y.d};
        }
        double det(const Mat2 &m) { return m.a*m.d - m.b*m.c; }
    }

    namespace stat {
        double media(const std::vector<double> &v) {
            return std::accumulate(v.begin(),v.end(),0.0) / v.size();
        }
        double varianza(const std::vector<double> &v) {
            double m=media(v), s=0;
            for(double x:v) s+=(x-m)*(x-m);
            return s/v.size();
        }
        double dev_std(const std::vector<double> &v) { return std::sqrt(varianza(v)); }
    }

    namespace trig {
        double sin_deg(double deg) { return std::sin(deg*PI/180); }
        double cos_deg(double deg) { return std::cos(deg*PI/180); }
        double tan_deg(double deg) { return std::tan(deg*PI/180); }
    }
}

int main() {
    using std::cout;
    math::algebra::Mat2 A{1,2,3,4}, B{5,6,7,8};
    auto C = math::algebra::mul(A,B);
    cout << "A*B = [[" << C.a << "," << C.b << "],[" << C.c << "," << C.d << "]]\n";
    cout << "det(A) = " << math::algebra::det(A) << "\n";

    std::vector<double> dati = {2,4,4,4,5,5,7,9};
    cout << "Media: "   << math::stat::media(dati) << "\n";
    cout << "Dev std: " << math::stat::dev_std(dati) << "\n";

    cout << "sin(30°) = " << math::trig::sin_deg(30) << "\n"; // 0.5
    cout << "cos(60°) = " << math::trig::cos_deg(60) << "\n"; // 0.5
    return 0;
}