Frage

Ich erlebte einige seltsame Verhalten während C ++ Typ Eigenschaften und haben mein Problem auf diesem schrulligen kleines Problem verengt, für die ich eine Tonne Erklärung geben, da will ich nichts für Fehlinterpretationen offen lassen.

Angenommen, Sie haben ein Programm wie folgt:

#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 den beiden 32-Bit-Kompilierung mit GCC (und mit 32- und 64-Bit-MSVC), die Ausgabe des Programms wird sein:

int:           0
int64_t:       1
long int:      0
long long int: 1

Doch das Programm aus einer 64-Bit-GCC kompilieren Ausgabe:

int:           0
int64_t:       1
long int:      1
long long int: 0

Das ist merkwürdig, da long long int ist ein signiertes 64-Bit-Integer und ist für alle Absichten und Zwecke, identisch mit den long int und int64_t Typen, so logisch, int64_t, long int und long long int wären gleichwertige Typen - die Anordnung erzeugt wird, wenn diese Art verwendet, ist identisch. Ein Blick auf stdint.h sagt mir, warum:

# if __WORDSIZE == 64
typedef long int  int64_t;
# else
__extension__
typedef long long int  int64_t;
# endif

In einer 64-Bit-Kompilierung, int64_t ist long int, kein long long int (offensichtlich).

Das Update für diese Situation ist recht einfach:

#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif

Aber das ist schrecklich hackish und skaliert nicht gut (tatsächliche Funktionen der Substanz, uint64_t, etc). Meine Frage ist also: Gibt es eine Möglichkeit, den Compiler zu sagen, dass ein long long int ist auch ein int64_t, wie long int ist


Meine erste Gedanken sind, dass dies nicht möglich ist, aufgrund der Art und Weise C / C ++ Typdefinitionen arbeiten. Es gibt keine Art und Weise Art Gleichwertigkeit der grundlegenden Datentypen an den Compiler zu spezifizieren, da die Aufgabe des Compilers (und ermöglicht, dass eine Menge Dinge brechen könnte) und typedef geht nur in eine Richtung.

Ich bin auch auch nicht darum, hier eine Antwort bekommen, da dies ein super-duper Rand Fall, dass ich nicht Verdächtiger jemand jemals kümmern, wenn die Beispiele nicht schrecklich ersonnen (bedeutet, dass diese Gemeinschaft sein sollte Wiki?).


anhänge : Der Grund, warum ich bin mit partieller Vorlage Spezialisierung statt einem einfacheren Beispiel wie:

void go(int64_t) { }

int main()
{
    long long int x = 2;
    go(x);
    return 0;
}

ist, dass dieses Beispiel noch kompilieren, da long long int zu einem int64_t implizit konvertierbar ist.


anhängen : Die einzige Antwort, so weit geht davon aus, dass ich wissen will, ob ein Typ 64-Bit. Ich wollte nicht zu verleiten Menschen zu denken, dass ich über die Pflege und wahrscheinlich sollte weitere Beispiele zur Verfügung gestellt haben, wo dieses Problem manifestiert sich.

template <typename T>
struct some_type_trait : boost::false_type { };

template <>
struct some_type_trait<int64_t> : boost::true_type { };

In diesem Beispiel wird some_type_trait<long int> ein boost::true_type, aber some_type_trait<long long int> wird nicht sein. Während dieser Sinn in C ++ die Idee der Typen macht, ist es nicht wünschenswert ist.

Ein weiteres Beispiel einen Qualifizierer wie same_type verwendet (die Verwendung in C ist sehr verbreitet ++ 0x Konzepte):

template <typename T>
void same_type(T, T) { }

void foo()
{
    long int x;
    long long int y;
    same_type(x, y);
}

versagt, dieses Beispiel zu kompilieren, da C ++ (korrekt) erkennt, dass die Arten unterschiedlich sind. g ++ fehl mit einem Fehler wie zu kompilieren. keine passenden Funktionsaufruf same_type(long int&, long long int&)

Ich möchte betonen, dass ich verstehe, Warum dies geschieht, aber ich bin auf der Suche für eine Abhilfe, die mich nicht Code zwingt zu wiederholen alle über dem Platz.

War es hilfreich?

Lösung

Sie müssen nicht auf 64-Bit gehen, so etwas zu sehen. Betrachten Sie int32_t über gemeinsame 32-Bit-Plattformen. Es könnte als typedef oder als int long'ed werden, aber natürlich nur eine der beiden auf einmal. int und long sind natürlich unterschiedliche Typen.

Es ist nicht schwer zu sehen, dass es keine Abhilfe, die int == int32_t == long auf 32-Bit-Systemen macht. Aus dem gleichen Grund gibt es keine Möglichkeit long == int64_t == long long auf 64-Bit-Systeme zu machen.

Wenn Sie könnten, die möglichen Folgen eher schmerzhaft für Code wäre, dass überladene foo(int), foo(long) und foo(long long) -?! Plötzlich sie zwei Definitionen für die gleiche Überlastung haben würde

Die richtige Lösung ist, dass Ihre Template-Code sollte in der Regel nicht auf eine genaue Art angewiesen sein, sondern auf die Eigenschaften dieses Typs. Die ganze same_type Logik noch in Ordnung für bestimmte Fälle geben könnte:

long foo(long x);
std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t);

d. Wird die Überlastung foo(int64_t) nicht definiert, wenn es genau die gleichen wie foo(long).

[Bearbeiten] Mit C ++ 11, haben wir jetzt einen Standard-Weg, dies zu schreiben:

long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);

Andere Tipps

Möchten Sie wissen wollen, ob eine Art vom gleichen Typ wie int64_t oder wollen Sie wissen, ob etwas 64 Bits ist? Basierend auf Ihre vorgeschlagene Lösung, ich glaube, Sie über die letzteren sind zu fragen. In diesem Fall würde ich so etwas wie

template<typename T>
bool is_64bits() { return sizeof(T) * CHAR_BIT == 64; } // or >= 64

Also meine Frage ist: Gibt es eine Möglichkeit, den Compiler zu sagen, dass ein langen, langes int ist auch ein int64_t, wie lange int

Dies ist eine gute Frage oder ein Problem, aber ich vermute, die Antwort NEIN ist.

Auch ein long int kann kein long long int sein.


# if __WORDSIZE == 64
typedef long int  int64_t;
# else
__extension__
typedef long long int  int64_t;
# endif

Ich glaube, dies ist libc. Ich vermute, Sie tiefer gehen wollen.

In den beiden 32-Bit-Kompilierung mit GCC (und mit 32- und 64-Bit-MSVC), die Ausgabe des Programms wird sein:

int:           0
int64_t:       1
long int:      0
long long int: 1

32-Bit-Linux verwendet das ILP32 Datenmodell. Die ganzen Zahlen, longs und Zeiger sind 32-Bit. Der 64-Bit-Typ ist ein long long.

Microsoft Dokumente die Bereiche unter Datentyp Rang . Das sagt die long long entspricht __int64.

Doch das Programm aus einer 64-Bit-GCC kompilieren Ausgabe:

int:           0
int64_t:       1
long int:      1
long long int: 0

64-Bit-Linux verwendet das LP64 Datenmodell. Longs sind 64-Bit und long long sind 64-bit. Wie bei den 32-Bit, die Bereiche Microsoft-Dokumente unter Datentyp Rang und lange, lange noch __int64.

Es gibt ein ILP64 Datenmodell, wo alles 64-bit ist. Sie haben einige zusätzliche Arbeit zu tun, um eine Definition für Ihren word32 Typen zu erhalten. Siehe auch Papiere wie 64-Bit Programmiermodelle: Warum LP64

?

Aber das ist schrecklich hackish und skaliert nicht gut (tatsächliche Funktionen der Substanz, uint64_t, etc) ...

Ja, es kommt noch besser. GCC-Mischungen und Streichhölzer Erklärungen, die angeblich 64-Bit-Typen zu nehmen, so dass ihre leicht in Schwierigkeiten zu bringen, auch wenn Sie ein bestimmtes Datenmodell folgen. Beispielsweise verursacht die folgende einen Compiler-Fehler und sagen Sie, zu verwenden -fpermissive:

#if __LP64__
typedef unsigned long word64;
#else
typedef unsigned long long word64;
#endif

// intel definition of rdrand64_step (http://software.intel.com/en-us/node/523864)
// extern int _rdrand64_step(unsigned __int64 *random_val);

// Try it:
word64 val;
int res = rdrand64_step(&val);

Es ergibt sich:

error: invalid conversion from `word64* {aka long unsigned int*}' to `long long unsigned int*'

Also, ignorieren LP64 und ändern Sie es an:

typedef unsigned long long word64;

Dann wandern über auf einen 64-Bit-ARM-IoT-Gadget, das definiert LP64 und Verwendung NEON:

error: invalid conversion from `word64* {aka long long unsigned int*}' to `uint64_t*'
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top