Я відчував певну дивну поведінку під час використання рис типу C ++ і звузив свою проблему до цієї химерної маленької проблеми, для якої я дам масу пояснень, оскільки не хочу залишати нічого відкритим для неправильного тлумачення.
Скажімо, у вас така програма:
#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;
}
І в 32-розрядному компілюванні з GCC (і в 32- і 64-розрядному MSVC) результат програми буде таким:
int: 0
int64_t: 1
long int: 0
long long int: 1
Однак програма, отримана в результаті 64-розрядної компіляції GCC, видасть:
int: 0
int64_t: 1
long int: 1
long long int: 0
Це цікаво, оскільки long long int
є 64-розрядним цілим числом із підписом і для всіх намірів і цілей ідентично типам long int
and int64_t
, що логічно int64_t
, long int
і long long int
буде еквівалентними типами - збірка, створена при використанні цих типів, ідентична. Один погляд на це stdint.h
говорить мені, чому:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
У 64-розрядної компіляції int64_t
є long int
, а не long long int
(очевидно).
Виправити ситуацію досить просто:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
Але це жахливо хакі і погано масштабується (фактичні функції речовини uint64_t
тощо). Тож моє запитання: чи є спосіб сказати компілятору, що a long long int
- це також a int64_t
, так само, як long int
є?
Я спочатку думав, що це неможливо через те, як працюють визначення типів C / C ++. Немає способу вказати еквівалентність типів основних типів даних компілятору, оскільки це робота компілятора (і дозволяючи, що може зламати багато речей) і typedef
проходить лише один шлях.
Я також не надто стурбований тим, щоб отримати тут відповідь, оскільки це надзвичайний випадок, про який я не підозрюю, що комусь коли-небудь буде все одно, коли приклади не жахливо надумані (чи означає це, що це має бути wiki-спільнота?) .
Додаток : Причина, чому я використовую часткову спеціалізацію на шаблонах замість більш простого прикладу, наприклад:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
полягає в тому, що згаданий приклад все одно буде компілюватися, оскільки long long int
неявно конвертується вint64_t
.
Додаток : Поки що єдина відповідь передбачає, що я хочу знати, чи є тип 64-бітовим. Я не хотів вводити людей в оману, думаючи, що я піклуюся про це, і, мабуть, мав би навести більше прикладів того, як ця проблема проявляється.
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
У цьому прикладі some_type_trait<long int>
буде a boost::true_type
, алеsome_type_trait<long long int>
не буде. Хоча це має сенс у уявленні про типи типів на C ++, це не бажано.
Інший приклад - використання такого кваліфікатора, як same_type
(який досить часто використовується у C ++ 0x Concepts):
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
Цей приклад не вдається скомпілювати, оскільки C ++ (правильно) бачить, що типи різні. g ++ не вдасться скомпілювати з помилкою типу: відсутність відповідного виклику функціїsame_type(long int&, long long int&)
.
Я хотів би наголосити, що розумію, чому це відбувається, але я шукаю обхідний шлях, який не змушує мене повторювати код повсюдно.
sizeof
кожного типу? Можливо, компілятор по-long long int
різному ставиться до розміру .