Я испытал странное поведение при использовании черт типа 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&)
.
Я хотел бы подчеркнуть, что я понимаю почему это происходит, но я ищу обходной путь, который не заставляет меня повторять код повсюду.
sizeof
каждого типа? Возможно, компилятор по-другому трактует размерlong long int
. - person Blair Holloway   schedule 12.11.2010<cstdint>
, поэтому, возможно, тот факт, что он должен сказать, что это расширение (а это так), его обманывает. - person GManNickG   schedule 12.11.2010--std=c++0x
. И да,sizeof(long long int) == sizeof(long int) == sizeof(int64_t) == 8
. - person Travis Gockel   schedule 12.11.2010long
иlong long
- разные типы (даже если они имеют одинаковый размер и представление).int64_t
всегда является псевдонимом для другого существующего типа (несмотря на свое имя,typedef
не создает новые типы, а просто дает псевдоним для уже существующего) - person M.M   schedule 20.03.2015int16_t
, тогда специализируйтесь наshort
иint
, и вы будете защищены. (и сsigned char
, если вы любите приключения) - person Irfy   schedule 03.02.2016