ho sperimentato un po 'strano comportamento durante l'utilizzo di C tipo tratti ++ ed ho ridotto il mio problema fino a questo piccolo problema eccentrico per la quale io darò un sacco di spiegazione dal momento che non voglio lasciare tutto aperto a interpretazioni errate.C++: long long int vs long int vs int64_t
Diciamo che avete un programma in questo modo:
#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;
}
sia a 32-bit compilare con GCC (e con 32 e 64 bit MSVC), l'output del programma sarà:
int: 0
int64_t: 1
long int: 0
long long int: 1
Tuttavia, il programma risultante da un 64-bit GCC compilare stamperà:
int: 0
int64_t: 1
long int: 1
long long int: 0
è curioso, poiché 0.123.è un numero intero a 64 bit ed è 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
mi dice perché:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
In un 64-bit di compilazione, int64_t
è long int
, non un long long int
(ovviamente).
La correzione di questa situazione è piuttosto semplice:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
Ma questo è terribilmente hacker e non scala bene (funzioni reali di sostanza, uint64_t
, ecc). ci è un modo per dire al compilatore che una long long int
è il anche una int64_t
, proprio come long int
è: Quindi la mia domanda è?
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 di tipo dei tipi di dati di base al compilatore, dal momento che è il lavoro del compilatore (e che consente di rompere un sacco di cose) e typedef
va solo in un modo.
Anche io non sono troppo preoccupato di ottenere una risposta qui, poiché si tratta di un caso limite super-duper che non sospetto che a nessuno interesserà mai quando gli esempi non sono orribilmente inventati (vuol dire che questo dovrebbe essere wiki della comunità?).
Append: Il motivo per cui sto utilizzando il modello di specializzazione parziale, invece di un esempio più semplice del tipo:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
è che ha detto ad esempio sarà ancora la compilazione, dal momento che long long int
è implicitamente convertibile in una int64_t
.
Append: L'unica risposta presuppone finora che voglio sapere se un tipo è 64-bit. Non volevo indurre in errore le persone a pensare che mi interessi e probabilmente avrei dovuto fornire altri esempi di dove questo problema si manifesta.
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à un boost::true_type
, ma some_type_trait<long long int>
non sarà. Mentre questo ha senso nell'idea di tipi del C++, non è desiderabile.
Un altro esempio sta usando un qualificatore come same_type
(che è abbastanza comune l'uso in C++ 0x Concetti):
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
Questo esempio non riesce a compilare, in quanto C++ (correttamente) vede che i tipi sono diverso. g ++ non riuscirà a compilare con un errore del tipo: nessuna funzione corrispondente chiamata same_type(long int&, long long int&)
.
Mi piacerebbe sottolineare che capisco perché questo sta accadendo, ma sto cercando una soluzione che non mi costringa a ripetere il codice in tutto il luogo.
Per curiosità, il programma di esempio fornisce gli stessi risultati per il 'sizeof' di ogni tipo? Forse il compilatore sta trattando le dimensioni di "long long int" in modo diverso. –
Hai compilato con C++ 0x abilitato? C++ 03 non ha '', quindi forse il fatto che abbia da dire "questa è un'estensione" (che è) lo sta facendo sembrare pazzo. –
GManNickG
Sì, avrei probabilmente specificato che sto usando '--std = C++ 0x'. E sì, 'sizeof (long long int) == sizeof (long int) == sizeof (int64_t) == 8'. –