Newsgroup: it.comp.lang.c++
Titolo: std::

Ciao a tutti!
Ho guardato un po' di post e ho notato che in molti casi citate le 
istruzioni esplicitando il prefisso "std::". Io uso sempre "using namespace 
std" all'inizio del codice e poi non ci penso piu'. Che controindicazioni ci 
sono? Grazie.
Ciao ciao 

 sono?
In piccoli esempi o esercizi, nessuna. Però così facendo annulli
completamente tutti i benefici offerti dall'aver messo la libreria
standard nel namespace std e quindi secondo me è meglio abituarsi al
prefisso std:: fin dall'inizio.
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
The EMG Music page:         
http://www.emagsoftware.it/emgmusic

 prefisso std:: fin dall'inizio.
O in alternativa utilizzare le direttive d'uso invece delle dichiarazioni
come segue:
using std::nome_mebro
in particolare
using::cout
using::cin
using::string
etc...
Ciao

 using::string
Personalmente non le amo. :-)


 Personalmente non le amo. :-)
Anche io uso sempre std:: ma sai se in un sorgente ci sono un sacco di
string da usare, potrebbe essere utile :)
Ciao

Io invece uso esclusivamente i nomi completamente specificati negli
header, per evitare contaminazioni indesiderate, ma non mi faccio
problemi ad inserire direttive using nei file .cpp . L'uso esclusivo di
nomi completamente specificati limita la generalita' dei template e
comunque preferisco individuare eventuali conflitti il prima possibile
ed utilizzare i nomi qualificati solo quando servono effettivamente.
Devo pero' dire che questo lo faccio piu' per i miei namespace che per
la libreria standard, dove mi sono abituato a specificare sempre std::
Ciao,
Nicola

 prefisso std:: fin dall'inizio.
Mumble, mumble... Allora forse mi sfugge l'utilità dei namespace...
Avevo capito che i namespace esistessero proprio per permettere di poter
usare nomi semplici e significativi, senza preoccuparsi del fatto che gli
stessi nomi possano essere usati altrove.
Avevo cioè capito che, grazie ai namespace, se nella mia libreria "frutteto"
scrivo una classe che implementa un'albicocca la posso chiamarla
semplicemente "albicocca"; se poi scopro che l'autore della libreria
"supermercato" ha scritto anche lui una classe di nome "albicocca", posso
risolvere il conflitto qualificando i nomi con i rispettivi namespace:
"frutteto::albicocca" vs. "supermercato::albicocca".
Ma farò questo solo nei moduli che devono usare contemporaneamente i due
diversi "albicocca" dai due diversi namespace: dove questo conflitto non
esiste, scrivo "albicocca", lasciando che la direttiva "using" a inizio
modulo mi disambigui gli identificatori.
Se io devo *sempre* qualificare i nomi, anche in assenza di un conflitto,
qual è il vantaggio di usare i namespace rispetto al vecchio sistema delle
naming convention complesse fatte di prefissi, suffissi, ecc.? Tanto vale
che io chiami la mia classe "frutteto_albicocca", l'altro programmatore la
chiami "SupermercatoAlbicocca", e così via.
--
Cingar
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/


Infatti si parlava (o per lo meno io mi riferivo) a std::. In effetti
per propri namespace i problemi sono completamente diversi e possono
portare a scelte diverse.


 Mumble, mumble... Allora forse mi sfugge l'utilità dei namespace...
Davo per scontato si parlasse del solo std. Per gli altri namespace le
scelte possono essere diverse.


Ma anche rispetto a std si puo' discutere. Per esempio e' illegale
definire un overload di una funzione appartenente a std, quindi se vuoi
implementare ad esempio swap() per una tua classe devi farlo in un tuo
namespace. Quindi se vuoi usare swap in un tuo template non puoi che
ricorrere ad una dichiarazione o a una direttiva using.
Ciao,
Nicola


Probabilmente hai ragione ma sei già oltre la mia possibilità di
comprensione. :-)


 comprensione. :-)
Anchio non ho capito. Faccio delle domande nel codice:
#include<set>
#include<iostream>
struct A { }; // la mia classe
namespace std {
    template<> void swap<A>(A &a, A &b) {
        cout << "specialization" << endl;
    }
    void swap(A &a, A &b) {
        cout << "overload" << endl;
    }
} // cosa dovrebbe essere stato illegale ?
void std::swap(A &a, A& b) {
        cout << "global namespace" << endl;
} // ... sicuramente questo
namespace my {
    void std::swap(A &a, A &b) {
        cout << "my namespace" << endl;
    } // ... e questo
    template<typename T>
    void f() {
        T a,b ;
        std::swap<T>(a,b);
        std::swap(a,b);
        // non ho usato dichiarazioni ne using nel mio template
    };
}
int main()
{
    my::f<A>(); // stampa "specialization" e "overload"
}
g++ 3.4
-- 
int

     } // ... e questo
Questa corrisponde a ::my::std::swap(). L'errore e' che il namespace
::my::std non e' stato definito.
Se vuoi ridefinire swap() per una tua classe la tua prima versione,
ovvero la specializzazione, e' una soluzione perfettamente valida. Ora
supponi di voler ridefinire swap() per una classe template, ad esempio
namespace my { template <typename T> class B {}; }
La via della specializzazione non e' piu' percorribile perche' non
esistono le specializzazioni parziali per le funzioni template. Devi
per forza ricorrere all'overload, che pero' non puo' stare in std:: .
La cosa piu' sensata e' scrivere
namespace my {
template <typename T> void swap(B<T> & first, B<T> & second);
}
Se a questo punto hai una funzione tipo
template <typename T> void f() {
  T a;
  T b;
  /* ??? :: */swap(a, b);
}
e vuoi chiamarla anche su B, come fai?
Ciao,
Nicola

 e vuoi chiamarla anche su B, come fai?
Per quanto detto sopra, std::swap.
Saluti
-- 
int

 Ancora non capisco perchè l'overload non puo' stare nel namespace
std.
Perche' il namespace std e' riservato a chi implementa compilatore e
libreria standard. L'unica cosa che ti e' consentito infilarci sono
specializzazioni di template della libreria standard su tipi da te
definiti.
Il succo del discorso e': fa come ti pare, ma se poi non funziona non
ti lamentare.
Ciao,
Nicola



E perchč non dovrei? Se la mia specializzazione, per essere usabile
*deve* stare in ::std e la rendo visibile in tutti i moduli, *deve*
poter funzionare.
Se poi non posso specializzare, *devo* ricorrere all'overload, ma sempre
in ::std *devo* rimanere.
Č il linguaggio che mi *obbliga* a fare questo.
... almeno, per quella parte del linguaggio che io conosco.
E poi perché l'overload č undefined behaviour? Non dovrebbe esserlo solo
nel caso di conflitto di overload/specialization di funzioni template?
Saluti
-- 
int

 nel caso di conflitto di overload/specialization di funzioni
template?
Non e' un problema tecnico, ma di convenzione. Il namespace std e'
riservato.
Ciao,
Nicola

 nel caso di conflitto di overload/specialization di funzioni template?
Umh... non sono sicuro di quanto dico ma penso che tale decisione sia stata
presa per evitare che le funzioni STL ben ottimizzate e performanti siano
nascoste da funzioni meno efficienti.
Se ad es. sovraccarichi swap per un tipo specifico e per il quale la swap
offerta dalla STL si mostra essere migliore perderesti tutti i vantaggi
della swap originale. In quei casi e' probabilmente meglio chiamare swap in
altro modo evitando l'overload.
Ciao

>e vuoi chiamarla anche su B, come fai?
Qui ADL non ha argomenti a cui appigliarsi :-) e occorre specificare
il tipo T.
Allego un pezzetto di codice che cerca di illustrare come stanno le cose:
#include <algorithm>
#include <iostream>
struct A {
   A(int i): x(i) { }
   int x;
};
void swap(A& lhs, A& rhs) {
   std::cout << "global swap\n";
   std::swap(lhs, rhs);
}
namespace ns {
   struct A {
     A(int i): y(i) { }
     int y;
   };
   void swap(A& lhs, A& rhs) {
     std::cout << "ns swap\n";
     std::swap(lhs, rhs);
   }
   template <typename T>
   void swap(T& lhs, T& rhs) {
     std::cout << "template ns swap\n";
     std::swap(lhs, rhs);
   }
}
 
namespace other {
   struct A {
     A(int i): z(i) { }
     int z;
   };
 
   template <typename T>
   void swap(T& lhs, T& rhs) {
     std::cout << "other swap\n";
     std::swap(lhs, rhs);
   }
}
 
namespace last {
   template <typename T>
   struct A {
     A(T i): q(i) { }
     int q;
   };
 
   template <typename T>
   void swap(A<T>& lhs, A<T>& rhs) {
     std::cout << "last swap\n";
     std::swap(lhs, rhs);
   }
}
template <typename T> void f() {
   T a(1);
   T b(2);
 
   std::cout << "void f\n";
   swap(a, b);
}
 
 
int main() {
   int a = 1;
   int b = 2;
 
   A aa(1);
   A bb(2);
 
   std::swap(a, b);
   std::cout << "a = " << a << ", b = " << b << "\n";
 
   std::swap(aa, bb);
   std::cout << "aa = " << aa.x << ", bb = " << bb.x << "\n";
 
   swap(aa, bb);
   std::cout << "aa = " << aa.x << ", bb = " << bb.x << "\n";
 
   ns::A aaa(1);
   ns::A bbb(2);
 
   std::swap(aaa, bbb);
   std::cout << "aaa = " << aaa.y << ", bbb = " << bbb.y << "\n";
 
 
   swap(aaa, bbb);
   std::cout << "aaa = " << aaa.y << ", bbb = " << bbb.y << "\n";
 
   other::A a4(1);
   other::A b4(2);
 
   std::swap(a4, b4);
   std::cout << "a4 = " << a4.z << ", b4 = " << b4.z << "\n";
 
   swap(a4, b4);
   std::cout << "a4 = " << a4.z << ", b4 = " << b4.z << "\n";
 
   last::A<int> a5(1);
   last::A<int> b5(2);
 
   std::swap(a5, b5);
   std::cout << "a5 = " << a5.q << ", b5 = " << b5.q << "\n";
 
   swap(a5, b5);
   std::cout << "a5 = " << a5.q << ", b5 = " << b5.q << "\n";
   f<A>();
   f<ns::A>();
   f<other::A>();
   f<last::A<int> >();
}
Si noti che:
- tutte le volte che uso std::swap(), viene sempre e solo usato
   il template swap definito in std;
- quando uso swap(), lascio al compilatore la scelta di quale
   definizione di swap usare;
- si preferisce usare una funzione non template piuttosto che
   generare un template (questo è un trappolone con i tipi come
   int per via delle conversioni);
- nel caso di swap(aa, bb) sono definiti nel namespace globale
   e si usa la funzione globale, non std::swap;
- nel caso di swap(aaa, bbb) si usa ns::swap che viene preferito
   alla funzione template;
- nel caso di swap(a4, b4) non c'è niente da preferire e viene
   usata la funzione template other::swap<T>;
- lo stesso accade nel caso di swap(a5, b5);
- le quattro istanziazioni del template f non fanno che ribadire il
   concetto.
Barone Frankenstein

 altro modo evitando l'overload.
http://www.sgi.com/tech/stl/swap.html#2
[2] This implementation of swap makes one call to a copy constructor and
two calls to an assignment operator; roughly, then, it should be
expected to take about the same amount of time as three assignments. In
many cases, however, it is possible to write a specialized version of
swap that is far more efficient. Consider, for example, swapping two
vector<double>s each of which has N elements. The unspecialized version
requires 3*N assignments of double, but a specialized version requires
only nine pointer assignments. This is important because swap is used as
a primitive operation in many other STL algorithms, and because
containers of containers (list<vector<char> >, for example) are very
common. The STL includes specialized versions of swap for all container
classes. User-defined types should also provide specialized versions of
swap whenever it is possible to write one that is more efficient than
the general version.
-- 
int

 riservato.
  [lib.reserved.names] 17.4.3.1 Reserved names
1 It is undefined for a C++ program to add declarations or definitions
  to namespace std or namespaces within namespace std unless otherwise
  specified. A program may add template specializations for any standard
  library template to namespace std. Such a specialization (complete or
  partial) of a standard library template results in undefined behavior
  unless the declaration depends on a user-defined name of external
  linkage and unless the specialization meets the standard library
  requirements for the original template. 163)
163) Any library code that instantiates other library templates must be
     prepared to work adequately with any user-supplied specialization
     that meets the minimum requirements of the Standard.
[Il testo dello standard l'ho preso da un post di Nicola 19 dic 2001 su
 iclc++] :-)
Posso aggiungere in std solamente specializzazioni di template di std,
per queste specializzazioni posso usare solo tipi utente
queste specializzazioni devono soddisfare i requisiti del loro template,
chi implementa una libreria template standard è obbligato a rispettare
queste specializzazioni.
Tutto il resto è male.
Quindi, non posso fare overload come supponevo.
Ma posso fare una specializzazione.
Non posso fare una specializzazione parziale di una funzione template
(swap) perché il risultato sarebbe un overload del template di base.
(come ha scritto Nicola 5 post fa :-)
Quindi
    namespace my { template <typename T> class B {}; }
non posso fare
    template<> void std::swap(my::B<T>& , my::B<T>& )
    (compila ma è un overload, g++ -Q aiuta ...)
ma
    template<> void std::swap(my::B<int>&, my::B<int>& )
    ecc..
Inoltre, per rendere usabile questa roba con gli algoritmi delle
librerie (per esempio partition), devo specializzare anche
std::iter_swap a fronte degli iteratori.
Giusto?
Codice:
    #include<iterator>
    #include<iostream>
    struct A{
        A(int i_) : i(i_) {}
        void swap(A& t) { std::swap(i, t.i); }
        int i;
    };
    namespace std {
        template<> inline void swap(A& a, A& b) {
            cout << "specialization swap A" << endl;
            a.swap(b);
        }
        template<> inline void iter_swap(A* a , A* b ) {
            // solo se l'iterator per A corrisponde ad A* ...
            cout << "specialization iter_swap A*" << endl;
            swap( *a, *b );
        }
    }
    bool p(const A& a) { return a.i % 2; }
    int main()
    {
        A a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        const int N = sizeof(a)/sizeof(a[0]);
        using namespace std;
        partition(a, a + N, p );
        copy(a, a + N, ostream_iterator<A>(cout, " "));
    }
    std::ostream& operator<<(std::ostream& o, const A& a) {
        o << a.i;
    }
Output:
    specialization iter_swap A*
    specialization swap A
    specialization iter_swap A*
    specialization swap A
    1 9 3 7 5 6 4 8 2 10 
-- 
int

 two calls to an assignment operator; roughly, then, it should be
[CUT]
Ehm... questo articolo dice che la std::swap in molti casi puo' essere meno
efficiente? Se si, in alcuni casi e' piu' efficiente e quindi sarebbe
inopportuno sovraccaricarla. Se no, traduci in italiano quanto hai scritto
:P
Ciao

    il template swap definito in std;
template definito in std vuol dire quello generico,
ma se specializzi il template in std,
se è il caso, ti becchi quello specializzato,
namespace o no, che tu voglia o no :-)
specializzato non ha niente a che fare col namespace.
O sbaglio?
-- 
int

 O sbaglio?
Forse.
Io penso che se swap viene chiamato passando oggetti di tipo ns::A o
other::A o last::A<> la specializzazione di std::swap non viene considerata
(Koenig Lookup?).
Ciao

 Se no, traduci in italiano quanto hai scritto :P
Seee ... troppo complicato per me :P lo faccio fare ad altavista:
[2] Questa esecuzione dello scambio fa una chiamata ad un costruttore
della copia ed a due chiamate ad un operatore di assegnazione;
approssimativamente, allora, dovrebbe essere previsto per occorrere il
tempo quasi uguale come tre assegnazioni. In molti casi, tuttavia, è
possibile scrivere una versione specializzata dello scambio che è molto
più efficiente. Consideri, per esempio, scambiando due il vettore la s
ciascuno di che ha elementi di N. La versione unspecialized richiede le
assegnazioni 3*N del doppio, ma una versione specializzata richiede
soltanto nove assegnazioni dell'indicatore. Ciò è importante perché lo
scambio è usato come funzionamento primitivo in molte altre procedure di
STL e perché i contenitori dei contenitori (lista, per esempio) sono
molto comuni. Lo STL include le versioni specializzate dello scambio per
tutti i codici categoria del contenitore. I tipi prestabiliti
dall'utente dovrebbero anche fornire le versioni specializzate dello
scambio ogni volta che è possibile scrivere uno che è più efficiente
della versione generale.
Saluti :-)
-- 
int

 (Koenig Lookup?).
Ma le specializzazioni e la base si chiamano entrambe std::swap. Non
puoi distinguerle.
Ari-sbaglio? :-)
-- 
int

 ciascuno di che ha elementi di N.
Tutto adesso e' che chiaro piu' si.
Ciao :P

 puoi distinguerle.
Non ti seguo: quello che volevo dire e' che se invochi swap(ns::A&,
ns::A&)la std::swap non viene considerata, ne base ne specializzata.
Ciao

 specializzato non ha niente a che fare col namespace.
Sono due momenti ortogonali: ADL interviene nella scelta
di *quale* template prendere in considerazione, una volta
scelto il template si pone il problema di quale sua
eventuale specializzazione istanziare.
Barone Frankenstein

 generato un'istanza.
Hai dimostrato quello che ho detto.
Il "niente affatto" immagino si riferisca al fatto che al momento
dell'istanziazione di std::swap non c'è la specializzazione che voglio
fare usare, e se la specializzo dopo mi becco giustamente l'errore.
Questa parte era il mio "se è il caso" e forse ho fatto male a non
esplicarlo.
Se non hai la specializzazione (prima), che tu voglia o no, ti becchi
l'istanziazione di std::swap non specializzata.
Se hai la specializzazione (prima), che tu voglia o no, ti becchi
l'istanziazione di std::swap specializzata.
Saluti
-- 
int

 ns::A&)la std::swap non viene considerata, ne base ne specializzata.
Ok scusa avevo capito male.
-- 
int

 altro modo evitando l'overload.
Il caso di swap e' particolare, perche' e' una funzione fondamentale
per la scrittura di codice "Exception friendly", posto di garantire che
non lanci mai eccezioni. Per ottenere questo e' molto spesso necessario
specializzarla o definirne degli overload.
Ciao,
Nicola