Ho accettato la risposta di @ davidhigh perché penso che sia la soluzione più appropriata per la mia domanda come richiesto, tuttavia, nel mio codice attuale ho usato una soluzione diversa, e nel caso in cui aiuti gli altri, io descrivilo qui.
La mia soluzione si basa su un commento fatto da @immibis che purtroppo è stato cancellato da allora. Era qualcosa del tipo "Non si può fare facilmente usando il preprocessore?" Mi sono reso conto che è possibile utilizzare i macro C *_MAX
da climits
e la soluzione è molto semplice. Grazie a @immibis!
Ho applicato una protezione per il preprocessore a tutti i tipi che può causare un conflitto, sia per le varianti firmate che per quelle senza segno. Consisteva in size_t
, uintmax_t
, ssize_t
, ptrdiff_t
e intmax_t
.
Inoltre, come @tbleher ha sottolineato nel suo commento, a volte i tipi nominali delle stesse dimensioni possono essere diversi tipi reali, l'esempio in questione è unsigned long
e unsigned long long
. Infatti, sul mio attuale sistema sizeof(unsigned long) == sizeof(unsigned long long) == 8
, e idem per le varianti firmate. Anche se hanno le stesse dimensioni, sono considerati diversi tipi reali e non entrano in conflitto.
Il mio approccio è stato quello di definire prima una funzione per ciascuno dei tipi distinti garantiti, quindi definire un ordine concettuale per i tipi "in conflitto" e quindi istanziare progressivamente una definizione per ogni tipo in conflitto la cui dimensione è entrambe (1) maggiore delle dimensioni di [unsigned] long long
e (2) non è uguale alla dimensione di qualsiasi tipo in conflitto che si trova prima nell'ordinazione.
Ecco una demo:
#include <climits> // most integer limit macros, including SSIZE_MAX
#include <cstddef> // size_t, ptrdiff_t, [u]intmax_t
#include <cstdint> // SIZE_MAX, PTRDIFF_{MIN,MAX}, UINTMAX_MAX, INTMAX_{MIN,MAX}
#include <sys/types.h> // ssize_t
#include <cstdio>
// primary template
template<typename T> void f(void);
// declarations -- guaranteed not to cause conflicts; dups are allowed
template<> void f<unsigned char>(void);
template<> void f<unsigned short>(void);
template<> void f<unsigned int>(void);
template<> void f<unsigned long>(void);
template<> void f<unsigned long long>(void);
template<> void f<size_t>(void);
template<> void f<uintmax_t>(void);
template<> void f<char>(void);
template<> void f<short>(void);
template<> void f<int>(void);
template<> void f<long>(void);
template<> void f<long long>(void);
template<> void f<ssize_t>(void);
template<> void f<ptrdiff_t>(void);
template<> void f<intmax_t>(void);
int main(void) {
f<unsigned char>();
f<unsigned short>();
f<unsigned int>();
f<unsigned long>();
f<unsigned long long>();
f<size_t>();
f<uintmax_t>();
f<char>();
f<short>();
f<int>();
f<long>();
f<long long>();
f<ssize_t>();
f<ptrdiff_t>();
f<intmax_t>();
return 0;
} // end main()
// definitions -- must use preprocessor guard on conflictable types
template<> void f<unsigned char>(void) { std::printf("%d\n",1); }
template<> void f<unsigned short>(void) { std::printf("%d\n",2); }
template<> void f<unsigned int>(void) { std::printf("%d\n",3); }
template<> void f<unsigned long>(void) { std::printf("%d\n",4); }
template<> void f<unsigned long long>(void) { std::printf("%d\n",5); }
#if SIZE_MAX > ULLONG_MAX
template<> void f<size_t>(void) { std::printf("%d\n",6); }
#endif
#if UINTMAX_MAX > ULLONG_MAX && UINTMAX_MAX != SIZE_MAX
template<> void f<uintmax_t>(void) { std::printf("%d\n",7); }
#endif
template<> void f<char>(void) { std::printf("%d\n",8); }
template<> void f<short>(void) { std::printf("%d\n",9); }
template<> void f<int>(void) { std::printf("%d\n",10); }
template<> void f<long>(void) { std::printf("%d\n",11); }
template<> void f<long long>(void) { std::printf("%d\n",12); }
#if SSIZE_MAX > LLONG_MAX
template<> void f<ssize_t>(void) { std::printf("%d\n",13); }
#endif
#if PTRDIFF_MAX > LLONG_MAX && PTRDIFF_MAX != SSIZE_MAX
template<> void f<ptrdiff_t>(void) { std::printf("%d\n",14); }
#endif
#if INTMAX_MAX > LLONG_MAX && INTMAX_MAX != SSIZE_MAX && INTMAX_MAX != PTRDIFF_MAX
template<> void f<intmax_t>(void) { std::printf("%d\n",15); }
#endif
uscita sul mio sistema:
1
2
3
4
5
4
4
8
9
10
11
12
11
11
11
Così come si è scoperto, sul mio sistema, tutti i tipi di conflictable in effetti conflitto con i veri tipi unsigned long
e long
.
Un paio di limitazioni di questa soluzione sono che può funzionare solo per i tipi che hanno corrispondenti macro *_MAX
e non funziona per i tipi a virgola mobile, poiché il preprocessore non supporta l'aritmetica a virgola mobile e i confronti.
@immibis: come fa il preprocessore a sapere che 'sizeof (size_t) == sizeof (unsigned long)'? –
Un avvertimento: anche se 'sizeof (size_t) == sizeof (unsigned long)', non è garantito che siano dello stesso tipo. 'size_t' potrebbe anche essere un typedef a' unsigned long long'. – tbleher
@immibis Il preprocessore esegue solo l'elaborazione del testo. Non sa nulla della struttura del testo sottostante e quindi non può prevedere le dimensioni del tipo di dati C++. Suppongo che se le dimensioni di questi tipi fossero definite come macro di preprocessore in modo standard su tutte le piattaforme, allora si potrebbero usare condizionali per il preprocessore per confrontarle, ma non penso che esistano tali "macro standard". – bgoldst