Newsgroup: it.comp.lang.c++
Titolo: costruttore const

Una istanza di una classe può sapere da un suo costruttore se essa
stessa è stata istanziata "const" oppure no?
Saluti
-- 
int

No perche' la "const-anza" e' una proprieta' che si instaura al termine
dell'esecuzione del costruttore stesso (che, altrimenti, potrebbe fare
ben poco).
Per poter distinguere ti conviene usare una factory, o se stai
scrivendo un template, specializzare uno dei due casi in base
all'altro.
Ciao,
Nicola

 ben poco).
Cosa comporterebbe un'eventuale versione specifica dei costruttori per i
const?
(pseudo-codice)
    struct A {
            A();
            A() const; // chiamata solo se creato con const
    };
    int main() {
            A a; // A::A()
            A const ac; // A::A() const
    }
Non č niente di utile, perņ pensavo per esempio un costruttore che
potrebbe allocare risorse differentemente in base alla sua "const-anza".
Per esempio, uno string che non alloca memoria se const
    string const s("valore");
in questo caso s potrebbe tenersi il puntatore a "valore" senza farsi
strdup() o strlen()/new/strcpy() dal medesimo.
Saluti
-- 
int

 strdup() o strlen()/new/strcpy() dal medesimo.
Uhm... La copia deve farsela ugualmente, altrimenti questo codice non fa
quello che deve fare:
char cstr[] = "valore";
string const s(cstr);
cstr[0] = '\0';
Ciao.
-- 
Qual'e' il colmo per uno studente-lavoratore?
Avere un quadrato che si crede un rettangolo.

Il caso di int pero' e' diverso, ed e' garantito dallo standard che un
valore letterale di tipo stringa non cambia.
Da un certo punto di vista e' in effetti un peccato che le stringhe
letterali non abbiano automaticamente tipo const string.
Ciao,
Nicola

 letterali non abbiano automaticamente tipo const string.
Si, penso che in un certo senso sarebbe giusto far migrare, anche solo in
parte, il concetto di "string" all'interno del compilatore, cosi' da
eliminare del tutto le vecchie "char *" che popolano ancora i nostri
programmi... :-)

 programmi... :-)
Da un lato sarebbe bello.. ma per esempio poi ci sarebbero problemi con
una serie di chiamate che invece lavorano con char*. Problemi nel senso
che si romperebbe codice esistente.
-- 
[ RiK0                                ]
[ Go away! The internet is full!      ]
[ Non credo negli schemi non vincenti ]


Cosa succede qui:
template<char const *S> struct String { /* ... */ };
extern char const a[] = "thestring";
String< a > thestring;
? Saluti
PS: Prassi ormai consolidata scrivere codice a caso che compili, ma di
cui non si conosca il comportamento :-)
g++ 3.4
-- 
int

 che si romperebbe codice esistente.
Uhm... Credi? 
Sempre ragionando per ipotesi, se la nostra "string literal" fosse di tipo
"string const" e la classe string avesse un operatore di cast verso "const
char *" credo che il codice legacy potrebbe continuare a funzionare.
Vi sembra corretto?
Ciao!
Ah... Visto il periodo...
Buona Pasqua a tutti!!!
:-)


Uno std::string istanziato ha bisogno di avere del codice eseguito a
runtime per poter essere utilizzabile mentre un c-string literal no.
In pratica, il compilatore costruisce in un area di memoria spesso
riservata un pool di stringhe, ovverossia per ogni stringa interpreta
quello che abbiamo scritto nel sorgente tra doppi apici e appende un
\000 alla fine. L'indirizzo del primo carattere della stringa è il
valore del simbolo con cui la stringa verrà riferita nell'esecuzione del
programma.
Per std::string è diverso. Il simbolo usato, cioè il nome della
variabile, non può essere forgiato nell'object file perché c'è bisogno
di passare per il runtime per costruire l'oggetto, per invocare il
costruttore. Tutto questo vale quando la variabile ha scope globale o
riconducibile a tale, che ne so per esempio uno static.
Però un implementazione di string con il valore della stringa
templetizzato potrebbe superare questa cosa? Questo è in realtà il senso
dell'altro mio post. Solo che non ho capito come funziona un non-type
template parameter quando è un puntatore o un reference.
Saluti
-- 
int

 char *" credo che il codice legacy potrebbe continuare a funzionare.
Non saprei... 
Bisognerebbe vedere cosa intendi con "cast verso" (ovvero come lo
faresti tecnicamente). 
Ma direi che avere le stringhe che si convertono in puntatori a
carattere non mi farebbe impazzire logicamente (ovvero avere oggetti che
diventano puntatori automaticamente).
E poi mi sa che si scatenerebbero un buon numero di casi ambigui con una
regola del genere. 
In ObjectiveC (un altro soprainsieme del C, anzi soprainsieme in senso
molto piu` stringente di quanto non lo sia il C++) si aveva un problema
simile. Ovvero avere NSString (l'equivalente di std::string) letterali.
Apple e GNU (ovvero GNU, e di conseguenza Apple, non so come fossero le
cose nel vecchio NeXT, quindi magari GNU ha preso da li) hanno scelto di
rappresentarle con @ davanti. 
"ciao" e` una stringa C letterale.
@"ciao" un'istanza della classe NSString (NSString e` immutabile, quindi
nessun problema di const-ness)
Credo che se hanno scelto questa strada, una ragione pratica ci sia...
sarebbe comunque da indagare.


 
E' spiegato nella sezione 14.3.2 dello Standard, di cui riporto la parte
iniziale. 
  14.3.2 Template non-type arguments       [temp.arg.nontype]
  1  A template-argument for a non-type, non-template template-parameter
     shall be one of:
  -- an integral constant-expression of integral or enumeration type; or
  -- the name of a non-type template-parameter; or
  -- the name of an object or function with external linkage, 
     including function templates and function template-ids but excluding
     non-static class members, expressed as id-expression; or
  -- the address of an object or function with external linkage, including
     function templates and function template-ids but excluding non-static
     class members, expressed as & id-expression where the & is optional if
     the name refers to a function or array; or
  -- a pointer to member expressed as described in 5.3.1 .
  2 [Note: A string literal (2.13.4) is not an acceptable template-argument
    because a string literal is an object  with internal linkage. [Example:
  [...]
Max

     because a string literal is an object  with internal linkage. 
Sě, ma perche devono essere external linkage?
Comprendo che il compilatore per instanziare il template debba conoscere
l'indirizzo di memoria dell'oggetto mentre sta compilando, ma perchč
questo dovrebbe avvenire con "external linkage" e non con "internal
linkage"?
Saluti
-- 
int

In realta' potrebbero esistere soluzioni a questo problema, ad esempio
prevedendo l'esistenza di piu' tipi stringa dotati di operatori per
combinarli tra loro, oppure avendo un singolo tipo stringa che
all'interno utilizza uno smart pointer per puntare al proprio buffer,
in modo da distinguere i buffer allocati staticamente da quelli
allocati dinamicamente. Nel primo caso il layout dell'oggetto sarebbe
perfettamente definito in fase di compilazione.
Tutto questo pero' non risolve il problema della conversione implicita
a char * .
Ciao,
Nicola

Funziona cosi':
#include <iostream>
template<char const *S>
struct String
{
    static char const * value;
};
template<char const *S>
char const * String<S>::value = S;
extern char const a[] = "thestring";
String< a > thestring;
int main(int, char *[])
{
    std::cout << thestring.value << '\n';
    std::cin.get();
}
Ciao,
Nicola