Newsgroup: it.comp.lang.c++
Titolo: warning in template

Ecco un estratto di codice di una classe template con un costruttore 
template:
template<int digits>
class Fixed {
		int value;
  	public:
		template<int D>
		Fixed(const Fixed<D> &f)
			:value(D>digits?(f.internal()>>(D-digits)):
				(f.internal()<<(digits-D))) {
			}
	// ....
};
Funziona come deve, ma il compilatore si lamenta (con un warning) perchï¿œ 
teme che io stia facendo uno shift di una quantitï¿œ negativa. Come potete 
vedere, invece, il controllo D>digits serve proprio a fare lo shift 
nella direzione giusta. Siccome sia D che digits sono parametri di 
template il valore del controllo D>digits ï¿œ noto in compile time. Come 
posso farlo capire al compilatore? Non vorrei disabilitare il warning, 
che in altre situazioni potrebbe tornare utile...
E.

 che in altre situazioni potrebbe tornare utile...
Le operazioni di shift andrebbero fatte sempre e solo su variabili 
unsigned (anche perche' lo shift verso dx di un int negativo ti da un 
int positivo...), metti unsigned int la tua variable "value" e il 
warning dovrebbe scomparire.

                 (f.internal()<<(digits-D))) {
"f.internal()" non sarebbe altro che "value".


 warning dovrebbe scomparire.
Il warning non si lamenta del fatto che il primo argomento dello shift 
sia con segno. Si lamenta del fatto che il secondo argomento ï¿œ negativo:
Warning : (33118) out of range shift value (-3) will be masked to (29)
fixed.h line 258       (f.internal()<<(digits-D))) {
Comunque forse la soluzione ï¿œ mettere una conversione a (unsigned) 
sull'operando di destra... ora provo.
E.

 sull'operando di destra... ora provo.
Niente da fare! Incredibilmente, il codice:
int f(int x) {
	return  1<0?x<<(unsigned int)(-3):1;
}
dï¿œ comunque il warning:
Warning : (33118) out of range shift value (-3) will be masked to (29)
delme.cpp line 10    return  1<0?x<<(unsigned int)(-3):1;
nonostante l'espressione non verrï¿œ mai valutata e il numero negativo 
venga convertito... Questo mi pare veramente eccessivo!
E.

 venga convertito... Questo mi pare veramente eccessivo!
A me pare corretto, da un warning pure il GCC, mi sembra difficile 
shiftare un intero di circa 4 miliardi di bit (-3 castato ad unsigned e` 
0xfffffffc) :)
gabry@nevada:~$ g++ -Wall -c /tmp/tttt.cpp
/tmp/tttt.cpp: In function ‘int f(int)’:
/tmp/tttt.cpp:3: warning: left shift count >= width of type
Al contrario cosi' il GCC non da warning:
unsigned int abs(int x) {
     if (x < 0) return -x;
     else return x;
}
int f(int x) {
     return  1<0?x<<abs(3):1;
}

 }
sì, avevo visto che questa soluzione funziona. Ma devo essere sicuro che 
non venga fatta nessuna chiamata a funzione, neanche nella versione 
debug (dove le funzioni non vengono mai messe inline), perché questa 
parte di codice deve essere fortemente ottimizzata.
Seguendo il tuo suggerimento ho però provato anche quest'altra:
int f(int x) {
	return  0>1?x<<(1>0?-3:1):1;
}
che però, incredibilmente, continua a dare il warning! Significa che il 
compilatore si accorge nella verifica del warning che dentro la 
parentesi tonda c'è -3, valutando immediatamente che 1>0 è true. Però 
non si accorge che la prima alternativa dell'operatore ternario non 
verrà mai valutata, perchè 0>1 è false.... la cosa mi pare delirante...
Invece questa:
int f(int x) {
	return  0>1?x<<(0>1?-3:1):1;
}
funziona, ovviamente... Penso che propenderò per questa soluzione!
E.

 che però, incredibilmente, continua a dare il warning! Significa che il 
Perche' incredibilmente?
1 > 0 e' sempre vero, quindi il compilatore rimuove lo statement falso + 
interno e lascia:
0 > 1 ? x << - 3 : 1
Probabilmente non e` in grado di fare la stessa ottimizzazione qui, per 
eliminare il 0 > 1 iniziale, perche` x e` una variabile e probabilmente 
qualche regola gli impedisce di rimuovere codice che manipola una variabile.
Lo stesso comportamento lo ha anche il GCC, ho provato a scriverlo anche 
cosi' e da sempre il warning, anche con l'ottimizzatore attivo:
#include <iostream>
int f(int x) {
     if (1 < 0) {
	std::cerr << "Pippo!\n";
         return  x<< ((1 > 0 ) ? -3 : 1);
     }
     else
         return 1;
}
.... pero' all'interno del file oggetto NON c'e' la stringa Pippo, 
quindi con il GCC lo statement viene eliminato, ma  in una fase di 
compilazione in cui i warning sono gia` stati emessi!
Bye,
  Gabry

Il mio compilatore non da alcun warning.
Invece, mi sai dire come si istanzia un oggetto di questa classe?
template <int i> class A {
    public :
           int v;
           template <int j>
           A(const A<j>& a) : v(i + j) {}
};
Ho provato:
int main() {
     A<5> x(A<6>());
    Ma l'assegnamento successivo da errore:
     x.v = 10;
     request for member `v' in `x', which is of non-class type `A<5> ()
(A<6> (*)())'
}