Ho sperimentato un comportamento strano durante l'utilizzo di tratti di tipo C ++ e ho ristretto il mio problema a questo piccolo problema eccentrico per il quale darò un sacco di spiegazioni poiché non voglio lasciare nulla di aperto per interpretazioni errate.
Supponi di avere un programma come questo:
#include <iostream>
#include <cstdint>
template <typename T>
bool is_int64() { return false; }
template <>
bool is_int64<int64_t>() { return true; }
int main()
{
std::cout << "int:\t" << is_int64<int>() << std::endl;
std::cout << "int64_t:\t" << is_int64<int64_t>() << std::endl;
std::cout << "long int:\t" << is_int64<long int>() << std::endl;
std::cout << "long long int:\t" << is_int64<long long int>() << std::endl;
return 0;
}
In entrambe le compilazioni a 32 bit con GCC (e con MSVC a 32 e 64 bit), l'output del programma sarà:
int: 0
int64_t: 1
long int: 0
long long int: 1
Tuttavia, il programma risultante da una compilazione GCC a 64 bit produrrà:
int: 0
int64_t: 1
long int: 1
long long int: 0
Questo è curioso, poiché long long int
è un intero con segno a 64 bit ed è, a tutti gli effetti, identico ai tipi long int
e int64_t
, quindi logicamente int64_t
, long int
e long long int
sarebbero tipi equivalenti: l'assembly generato quando si utilizzano questi tipi è identico. Uno sguardo a stdint.h
me mi dice perché:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
In un 64-bit compilazione, int64_t
è long int
, non long long int
(ovviamente).
La soluzione per questa situazione è piuttosto semplice:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
Ma questo è orribilmente hacker e non scala bene (funzioni effettive della sostanza uint64_t
, ecc.). Quindi la mia domanda è: c'è un modo per dire al compilatore che a long long int
è anche a int64_t
, proprio come long int
è?
I miei pensieri iniziali sono che questo non è possibile, a causa del modo in cui funzionano le definizioni di tipo C / C ++. Non c'è un modo per specificare l'equivalenza del tipo dei tipi di dati di base al compilatore, poiché questo è il lavoro del compilatore (e consentire ciò potrebbe rompere molte cose) e typedef
va solo in un modo.
Inoltre, non sono troppo preoccupato di ottenere una risposta qui, dal momento che questo è un caso limite super-duper di cui non sospetto che a nessuno interesserà mai quando gli esempi non sono orribilmente inventati (significa questo dovrebbe essere un wiki della comunità?) .
Aggiungi : il motivo per cui sto utilizzando la specializzazione parziale del modello invece di un esempio più semplice come:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
è che detto esempio verrà comunque compilato, poiché long long int
è implicitamente convertibile in un file int64_t
.
Aggiungi : l'unica risposta fino ad ora presuppone che io voglia sapere se un tipo è a 64 bit. Non volevo indurre le persone a pensare che ci tenessi a questo e probabilmente avrei dovuto fornire più esempi di dove si manifesta questo problema.
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
In questo esempio, some_type_trait<long int>
sarà a boost::true_type
, ma some_type_trait<long long int>
non lo sarà. Sebbene questo abbia senso nell'idea di tipi di C ++, non è desiderabile.
Un altro esempio sta usando un qualificatore come same_type
(che è abbastanza comune da usare in C ++ 0x Concepts):
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
Quell'esempio non viene compilato, poiché C ++ (correttamente) vede che i tipi sono diversi. g ++ non riuscirà a compilare con un errore come: nessuna chiamata di funzione corrispondente same_type(long int&, long long int&)
.
Vorrei sottolineare che capisco perché sta accadendo, ma sto cercando una soluzione alternativa che non mi costringa a ripetere il codice ovunque.
sizeof
ogni tipo? Forse il compilatore tratta la dimensione di in modolong long int
diverso.