Newsgroup: it.comp.lang.c++
Titolo: Contare il numero di elementi in un enum

Supponiamo di avere l'esigenza di sapere quanti elementi ci sono in un enum.
enum RECORD_LEVEL	{
	RL_ERROR = 0,
	RL_WARNING,
	RL_SUGGESTION,
	RL_OK
};
Io ho pensato ad una soluzione come questa:
template<typename T, typename T Val = static_cast<T>( -1 ) >
struct EnumCounter
{
	enum {result = EnumCounter< T, (static_cast<T>(Val+1)) >::result};
};
template<>
struct EnumCounter<RECORD_LEVEL, RL_OK>	
{
	enum {result = 4};
};
cout << EnumCounter<RECORD_LEVEL>::result << endl;
Che dal punto di vista dell'usabilità non é male, visto che richiede solo di 
specificare la "condizione di uscita" con la specializzazione parziale del 
template, ed é piuttosto immediato accedere al valore che interessa.
Un primo problema salta fuori nel caso tutti i valori dell'enum siano 
negativi: ok, posso inizializzare il default a, diciamo, -1000, oppure 
richiedere un'inizializzazione esplicita.
D'altra parte di solito nel mondo c'é sempre qualcuno che ha un'idea migliore 
della tua, quindi... :-)
-- 
         Giuseppe "Cowo" Corbelli ~\/~ My software: 
http://cowo.yoda2000.net
-<! Non c'e' niente da dire in proposito. Tutto quello che uno deve fare e'
   colpire i tasti giusti al momento giusto, e lo strumento suona da solo. !>-
                                 J.S. Bach

 enum.
enum MyEnum    {
     MY_LOW    = -3,
     MY_NORMAL = 5,
     MY_ALIAS  = 5,
     MY_MAX    = 18
};


Beh, con l'implementazione che ho proposto basta aver definito
template<>
struct EnumCounter<MyEnum, MY_MAX>
{
     enum {result = 4};
};
e la baracca dovrebbe stare in piedi.


 };
E questo lo chiami "contare"? Hai già scritto il numero!
Inoltre la chiamata ricorsiva è totalmente inutile.
Ti basterebbe scrivere:
___
template<typename T>
struct EnumCounter;
template<>
struct EnumCounter<RECORD_LEVEL>
{
	static const int result = 4;
};
___
Ma ciò non può ugualmente dirsi /contare/.
Kiuhnm
Inviato da X-Privat.Org - Registrazione gratuita 
http://www.x-privat.org/join.php


Good point. Mi sono complicato la vita per niente.
Hai proposte alternative?


 Hai proposte alternative?
Ne ho una, ma ti consiglio di lasciare perdere.
Sfruttando la macro PL_FIND (trovi un mio post sul ng del C) è possibile 
scrivere una macro PARAMS che conti il numero di parametri passati ad 
essa. Allora è possibile scrivere una macro ENUM che ha una sintassi 
simile a quella consueta:
ENUM(RECORD_LEVEL,
      RL_ERROR = 0,
      RL_WARNING,
      RL_SUGGESTION,
      RL_OK);
Che produrrà
enum RECORD_LEVEL    {
      RL_ERROR = 0,
      RL_WARNING,
      RL_SUGGESTION,
      RL_OK,
      RECORD_LEVEL_NUMBER_OF_ITEMS = 4
};
A questo punto, implementata SIZE, si potrà scrivere:
SIZE(RECORD_LEVEL)


 Sfruttando la macro PL_FIND (trovi un mio post sul ng del C) è possibile 
Non sono sicuro che in C++ tu possa già scrivere macro con un numero 
variabile di argomenti

 };
Le uniche soluzioni fattibili mi sembrano definire:
   enum RECORD_LEVEL {
      RL_ERROR,
      RL_WARNING,
      RL_SUGGESTION,
      RL_OK,
      RL_ultimo
   };
e usare RL_ultimo, oppure definire:
   enum RECORD_LEVEL {
      RL_primo = 123, // se si vuole partire da 124
      RL_ERROR,
      RL_WARNING,
      RL_SUGGESTION,
      RL_OK,
      RL_ultimo
   };
e usare RL_ultimo - RL_primo.
Queste tecniche assumono che si aggiungano nuove costanti solamente dopo 
l'eventuale RL_primo e prima di RL_ultimo, e che le costanti abbiano 
valori consecutivi.
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

 migliore della tua, quindi... :-)
#include <iostream>
#define ENUM(NAME, ...)		\
	enum NAME				\
	{						\
		__VA_ARGS__			\
	};						\
							\
	namespace GeniusAtWork	\
	{						\
		int __VA_ARGS__;	\
							\
		int NAME[] =		\
		{					\
			__VA_ARGS__		\
		};					\
		const int NAME##_SIZE = sizeof(NAME)/sizeof(int);	\
	}
ENUM(RECORD_LEVEL,
	RL_ERROR = 0,
	RL_WARNING,
	RL_SUGGESTION,
	RL_OK,
	RL_STI_VA_ARGS_ = 238,
	RL_SONO_PROPRIO_,
	RL_NECESSARI,
	RL_VABBE_CHE_SONO_,
	RL_UN_GENIO_MA_,
	RL_ESISTONO_DEI_LIMITI_ = 98723,
	RL_INVALICABILI,
	RL_E_IMPRESCINDIBILI_,
	RL_INOLTRE_CE_UN_PROBLEMA_,
	RL_RIGUARDANTE_LO_SPRECO_DI_,
	RL_MEMORIA,
	RL_UN_COMPILATORE_VALIDO,
	RL_DOVREBBE_ELIMINARE_LE_VARIABILI = 12922,
	RL_INUTILIZZATE_A_RUNTIME,
	RL_QUINDI_IN_PRATICA_DOVREBBE_ANDARE_,
	RL_TUTTO_BENE_,
	RL_MA_LA_SOLUZIONE_NON_E_PERFETTA,
	RL_HO_FATTO_TUTTO_QUESTO_PER_EVITARE_DI_USARE,
	RL_PL_FIND_CHE_POTREBBE_SPAVENTARE_I_PIU,
	RL_CYA);
ENUM(VA_ANCHE_QUESTO,
	 VA_OK1 = -345,
	 VA_OK2 = -2,
	 VA_OK3,
	 VA_OK4);
int main()
{
	std::cout << "RECORD_LEVEL" << std::endl;
	std::cout << "size = " << GeniusAtWork::RECORD_LEVEL_SIZE << std::endl;
	std::cout << "RL_CYA = " << RL_CYA << std::endl;
	std::cout << std::endl;
	std::cout << "VA_ANCHE_QUESTO" << std::endl;
	std::cout << "size = " << GeniusAtWork::VA_ANCHE_QUESTO_SIZE << std::endl;
	std::cout << "VA_OK4 = " << VA_OK4 << std::endl;


 
ero sicuro che avresti sfornato una soluzione da preprocessor 
master. L'ho letta (perché mi intriga il PP) ma una cosa mi 
sfugge : cos'è la macro __VA_ARGS__ ? Dov'è definita ?
ciao
Soviet_Mario


 macro __VA_ARGS__ ? Dov'è definita ?
http://en.wikipedia.org/wiki/Variadic_macro
Il C++ la supporterà ufficialmente con la nuova revisione.
Kiuhnm