Ich habe @ davidhighs Antwort akzeptiert, weil ich denke, dass es die am besten geeignete Lösung für meine Frage ist, aber in meinem tatsächlichen Code habe ich eine andere Lösung verwendet und nur für den Fall, dass es anderen hilft, werde ich Beschreibe es hier.
Meine Lösung basiert auf einem Kommentar von @immibis, der leider gelöscht wurde. Es war so etwas wie "Kann man das nicht einfach mit dem Präprozessor machen?" Ich erkannte, dass die C *_MAX
Makros von climits
tatsächlich verwendet werden können, und die Lösung ist sehr einfach. Danke an @immibis!
Ich habe einen Präprozessor Guard auf alle Typen angewendet, die einen Konflikt verursachen können, sowohl für signierte als auch für unsignierte Varianten. Dieser bestand aus size_t
, uintmax_t
, ssize_t
, ptrdiff_t
und intmax_t
.
Auch, wie @tbleher in seinem Kommentar darauf hingewiesen hat, können manchmal nominale Typen gleicher Größe unterschiedliche wahre Typen sein, das Beispiel ist unsigned long
und unsigned long long
. In der Tat, auf meinem aktuellen System sizeof(unsigned long) == sizeof(unsigned long long) == 8
, und dito für die signierten Varianten. Obwohl sie die gleiche Größe haben, werden sie als verschiedene echte Typen betrachtet und stehen nicht in Konflikt.
Mein Ansatz bestand darin, zuerst eine Funktion für jeden der garantiert unterschiedlichen Typen zu definieren, dann eine konzeptuelle Sortierung für die "konfliktiven" Typen zu definieren und dann schrittweise eine Definition für jeden Konflikttyp zu initialisieren, dessen Größe sowohl (1) größer als die Größe von [unsigned] long long
und (2) nicht gleich der Größe eines Konflikttyps, der früher in der Bestellung sitzt.
Hier ist eine 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
Ausgang auf meinem System:
1
2
3
4
5
4
4
8
9
10
11
12
11
11
11
So wie sich herausstellte, auf meinem System, alle konflikt Typen mit den echten Typen in der Tat Konflikt tun unsigned long
und long
.
Ein paar Einschränkungen dieser Lösung sind, dass es nur für Typen mit entsprechenden *_MAX
Makros funktionieren kann, und es funktioniert nicht für Gleitkommatypen, da der Präprozessor Gleitkomma-Arithmetik und Vergleiche nicht unterstützt.
@immibis: Wie weiß der Präprozessor, dass 'sizeof (size_t) == sizeof (unsigned long)'? –
Ein Vorbehalt: Selbst wenn 'sizeof (size_t) == sizeof (unsigned long)' ist, ist nicht garantiert, dass sie vom selben Typ sind. 'size_t' könnte auch ein typedef zu 'unsigned long long' sein. – tbleher
@immibis Der Präprozessor verarbeitet nur Text. Es weiß nichts über die Struktur des zugrunde liegenden Textes und kann daher nicht auf C++ - Datentypgrößen predigen. Ich nehme an, wenn die Größen dieser Typen auf allen Plattformen als Präprozessor-Makros definiert wären, dann könnten Sie Präprozessor-Bedingungen verwenden, um sie zu vergleichen, aber ich glaube nicht, dass solche "Standard-Makros" existieren. – bgoldst