Я испытал странное поведение при использовании черт типа 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
не a 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
только в одном направлении.
Я также не слишком беспокоюсь о том, чтобы получить здесь ответ, поскольку это супер-пупер крайний случай, который, я не подозреваю, кого-то когда-либо будет волновать, когда примеры не будут ужасно надуманными (означает ли это, что это должна быть вики сообщества?) .
Приложение : причина, по которой я использую частичную специализацию шаблона вместо более простого примера, такого как:
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&)
.
Я хотел бы подчеркнуть, что понимаю, почему это происходит, но я ищу обходной путь, который не заставит меня повторять код повсюду.
sizeof
каждого типа? Возможно, компилятор по-long long int
другому трактует размер .