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

tempo fa avevo aggiunto a wikipedia un'implementazione template della 
funzione di ackermann. scopro ora che č stata rimossa dopo poco tempo 
con la motivazione che con gcc non compila. in effetti io l'ho provato 
solo su vc++ "strict", compila ed č corretto, eppure...
template<int x, int y>
struct ackermann {
  enum {
    v = ackermann<x-1, ackermann<x, y-1>::v>::v
  } ;
} ;
template< int y>
struct ackermann<0, y> {
  enum {
    v = y+1
  } ;
} ;
template<int x >
struct ackermann<x, 0> {
  enum {
    v = ackermann<x-1, 1>::v
  } ;
} ;
template<>
struct ackermann<0, 0>
{
  enum {
    v = 1
  } ;
} ;
qualche buon'anima che me lo proverebbe su gcc, e magari mi spiegasse 
(no, non sono molto abile di c++) cos'ha che non va? grazie :)

 qualche buon'anima che me lo proverebbe su gcc,
Compila perfettamente su GCC 4.1.0.
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
 

(no, non sono molto abile di c++) cos'ha che non va? grazie :)
Ho provato con gcc distribuito con mingw: compila perfettamente.

 Compila perfettamente su GCC 4.1.0.
Allora non capisco proprio. Non che mi stupisca, in fin dei conti è una 
cosa talmente banale e semplice. In effetti lo provai (e ho riprovato 
ora) a compilarlo con il Comeau online e pure lui nessun problema...
Mah.



Rimetticela su wikipedia :-)
Magari questa volta specifica che il codice, compilato sui diversi
compilatori (li citi con tanto di versione), non fa una grinza.

 Mah.
Confermo anche con il 4.1.1
Ciao.

 Confermo anche con il 4.1.1
Idem con GCC 4.2.2.


 } ;
E' facile compilare un template quando non viene istanziato: infatti il 
compilatore fa ben poco in tal caso.
La difficolta' si ha quando alle suddette istruzioni si aggiunge la 
seguente:
	ackermann<x, y>::v;
dove x e y sono due espressioni costanti intere.
Ho fatto qualche esperimento con il compilatore Visual C++ 7.1, 
ottenendo che:
* Per x = 0, compila per qualsiasi y positivo.
* Per x = 1, compila solo per y <= 562.
* Per x = 2, compila solo per y <= 560.
* Per x = 3, compila solo per y <= 8.
* Per x = 4, compila solo per y = 0.
* Per x > 4, non compila mai.
L'errore fornito e' sempre lo stesso, cioe':
fatal error C1202: tipo ricorsivo o contesto delle dipendenze di
una funzione troppo complesso
Inoltre, la clausola "template<> struct ackermann<0, 0>"
e' inutile, in quanto la precedente clausola
"template<int y> struct ackermann<0, y>" gestisce adeguatamente il caso 
<0, 0> e non e' ricorsiva.
Tuttavia, anche eliminandola i suddetti limiti non variano.
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

 compilatore fa ben poco in tal caso.
Vero, accidenti!


 compilatore fa ben poco in tal caso.
eh, infatti.
Ma mi chiedevo una cosa. Affinché una classe template venga 
compilata in ogni sua parte, è sufficiente istanziarla e farne 
un qualche uso, avendo la sicurezza che eventuali metodi e 
membri non usati vengano controllati, o bisogna capillarmente 
invocare ogni singolo metodo per avere tale certezza ?
Il dubbio mi è venuto perché in effetti una funzione mai 
invocata in modo diretto o indiretto, e di cui non si prenda mai 
nemmeno l'indirizzo, potrebbe anche essere trascurata, o mi 
sbaglio ?
Resto in attesa di un eventuale chiarimento su questo punto.
Ah, se è la seconda, qual'è il metodo più rapido per attivare il 
controllo sintattico su ogni parte di una classe, senza ancora 
entrare nel debug vero e proprio e quindi alla ricerca di errori 
di logica di funzionamento, ma solo per vedere la correttezza 
sintattica ? Potrebbe bastare prendere l'indirizzo di ogni 
funzione membro e metterlo in una variabile per forzare la 
istanziazione e compilazione del corpo della funzione ?
ciao
Soviet_Mario


 invocare ogni singolo metodo per avere tale certezza ?
Se una classe template viene istanziata implicitamente (ossia dichiarando un
oggetto di un tipo corrispondente a una istanziazione), soltanto le
funzioni membro effettivamente usate vengono istanziate.
Se una classe template viene instanziata esplicitamente (ossia mediante la
sintassi: template class C<T>), tutti le funzioni membro vengono istanziate
e la compilazione fallisce se l'istanziazione di almeno una non è
possibile.
Considera:
 template< class T >
 struct A
 {
        void func()
        { typename T::size_type i = 0;
        }
 };
Se dichiari un oggetto così:
  A<int> i;
la compilazione va a buon fine, a condizione che non venga usata la funzione
'func', che con T=int non può essere istanziata.
Se invece istanzi A<> esplicitamente:
 template class A<int>;
la compilazione non va a buon fine.
Max
 

 una funzione troppo complesso
Normale. Quel codice implementa la funzione di Ackermann, che è una 
funzione che non ha nessun utilizzo pratico se non dover fare una valanga 
di ricorsioni prima di dare il risultato.

 Mea culpa, non l'avevo scritto...
Se riporti l'esempio completo di main() con istanziazione te lo riprovo.


tipo predefinito, o meno.
http://www.google.it/search?q=size_type

Andrea Laforgia ha scritto:

grazie della segnalazione (in effetti non avevo cercato temendo 
la valanga di risultati, che poi c'è stata ma le prime voci 
erano già pertinenti, quindi sono stato pessimista a torto).
Ho letto alcune delle pagine riportate.
Ad es. size_type pare (pare a me, ovviamente, non so se sia 
vero) sia un membro di basic_string (e altri contenitori, 
allocatori etc).
Ma non ho capito di che genere di membro sia ... è una TYPEDEF ?
A prescindere dal fatto che sia un typedef o altro, come mai 
nell'esempio di Max Edgar (che forse me lo dirà lui stesso), era 
usato in un'altra classe senza lo scope risolutor adatto tipo
basic_string::size_type ?
Era proprio quella l'intenzione di generare un'errore di uso di 
un simbolo non definito nel contesto specifico ?
oppure è un simbolo globale ? Non richiede nessun prefisso di 
classe o namespace ? Se è questa, sono confuso
P.S.
conoscevo size_t (perché è il tipo implicato con sizeof, con new 
e varie altre funzioni), e a quanto ho visto di size_type è 
sostanzialmente un unsigned integral (è per questo che ho 
immaginato fosse un typedef definito chissà dove).
Come mai è stato introdotta un'altra denominazione per il 
medesimo concetto ?
cioè, c'è qualche differenza tra la vecchia size_t e la nuova 
size_type ? Quale, se c'è ?
ciao
Soviet_Mario

 riprovo. 
#include <iostream>
template<int x, int y>
struct ackermann {
  enum {
    v = ackermann<x-1, ackermann<x, y-1>::v>::v
  } ;
} ;
template< int y>
struct ackermann<0, y> {
  enum {
    v = y+1
  } ;
} ;
template<int x >
struct ackermann<x, 0> {
  enum {
    v = ackermann<x-1, 1>::v
  } ;
} ;
template<>
struct ackermann<0, 0>
{
  enum {
    v = 1
  } ;
} ;
int main()
{
  std::cout << ackermann<0,0>::v << std::endl ; // 1
  std::cout << ackermann<1,0>::v << std::endl ; // 2
  std::cout << ackermann<0,1>::v << std::endl ; // 2
  std::cout << ackermann<3,1>::v << std::endl ; // 13
  std::cout << ackermann<4,1>::v << std::endl ; // 65533
  std::cout << ackermann<3,2>::v << std::endl ; // 29
  std::cout << ackermann<3,4>::v << std::endl ; // 125
}
cosi dovrebbe compilare senza errori
tranne i normali "recursion limit" ovviamente
grazie di nuovo :)

 tranne i normali "recursion limit" ovviamente
Ottengo questi due errori:
ACKERMANN.cc:5: error: template instantiation depth exceeds maximum of 500 
(use -ftemplate-depth-NN to increase the maximum) instantiating
'struct ackermann<2, 528>'
ACKERMANN.cc:5: error: incomplete type 'ackermann<2, 528>' used in nested 
name specifier


Ma non ho capito di che genere di membro sia ... č una TYPEDEF ?
Sě e deve essere un tipo intero senza segno in grado di rappresentare
qualsiasi valore non negativo di difference_type. Appartiene alla
sfilza di "requirements" per i container (insieme a begin(), end(),
value_type(), iterator(), ecc...).

tranne i normali "recursion limit" ovviamente
Ti farà piacere sapere che il gcc, dopo averci pensato un po', mi
sputa fuori un:
"5 C:\Dev-Cpp\main.cpp template instantiation depth exceeds maximum of
500 (use -ftemplate-depth-NN to increase the maximum) instantiating
`struct ackermann<2, 528>'"
Seguito da una sfilza di messaggi: 
"5 C:\Dev-Cpp\main.cpp   instantiated from `ackermann<2, 529>'"
"5 C:\Dev-Cpp\main.cpp   instantiated from `ackermann<2, 528>'"
"5 C:\Dev-Cpp\main.cpp   instantiated from `ackermann<2, 527>'"
...
...
"5 C:\Dev-Cpp\main.cpp   instantiated from `ackermann<4, 1>'"
e conclude con un simpatico:
"[General Error] Too many messages; abort. There must be something
terribly wrong with your code. Please fix it."
:-)

 basic_string::size_type ?
Nel mio esempio 'size_type' non aveva alcun significato particolare. Avrei
potuto scriverci "pippo". L'idea era scrivere una funzione che poteva
essere istanziata soltanto se il tipo T avesse incorporato un
typename 'size_type'. 
Se provi a istanziare esplicitamente A<> con std::string o std::vector,
vedrai che il codice compila. Con 'int', no.
 
Tutto qui. Non ho capito che cosa ti ha lasciato perplesso.
Ti lascio con un esercizietto: 
Data la definizione di A<> che ho dato, definire -senza mai usare la
keyword 'typedef'- un tipo B tale che A<B> sia istanziabile esplicitamente.
'notte,
Max

 "There must be something terribly wrong with your code. Please fix it."
Ottimo, funziona *perfettamente* :)

 Max

 segnalamelo !
Non puoi inizializzare un enum con '0'.
Max

 terribly wrong with your code. Please fix it."
ROTFL :)
-- 
blog:  
http://www.akropolix.net/rik0/blogs
 | Uccidete i filosofi,
site:  
http://www.akropolix.net/rik0/
      | tenetevi riso e
forum: 
http://www.akropolix.net/forum/
     | bacchette per voi.

ROTFL :)
Il "Please" mi ha fatto ridere per un'ora :-)

 Il "Please" mi ha fatto ridere per un'ora :-)
Si, ha un che di surreale. Ma anche il 'terribly wrong' non scherza.


 Max