Я столкнулся с некоторым странным поведением при использовании черт типа 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
и 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
и т. Д.). Итак, мой вопрос: Есть ли способ сообщить компилятору, что long long int
- это тоже int64_t
, как long int
?
Сначала я думаю, что это невозможно из-за того, как работают определения типов C / C ++. Не существует способа указать эквивалентность типов базовых типов данных для компилятора, поскольку это является задачей компилятора (и допускает, что это может сломать много вещей), и typedef
идет только в одну сторону.
Я также не слишком заинтересован в том, чтобы получить ответ здесь, так как это сверхъестественный крайний случай, о котором я не подозреваю, что кого-то когда-нибудь волнует, когда примеры не придуманы ужасно (означает ли это, что это должно быть сообщество вики?).
Добавить : причина, по которой я использую частичную специализацию шаблонов вместо более простого примера, например:
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>
будет 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&)
.
Я хотел бы подчеркнуть, что я понимаю , почему это происходит, но я ищу обходной путь, который не заставляет меня повторять код повсюду.