Eu experimentei um comportamento estranho ao usar características do tipo C ++ e reduzi meu problema a este pequeno problema peculiar para o qual darei muitas explicações, já que não quero deixar nada aberto para interpretações erradas.
Digamos que você tenha um programa como este:
#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;
}
Na compilação de 32 bits com GCC (e com MSVC de 32 e 64 bits), a saída do programa será:
int: 0
int64_t: 1
long int: 0
long long int: 1
No entanto, o programa resultante de uma compilação GCC de 64 bits produzirá:
int: 0
int64_t: 1
long int: 1
long long int: 0
Isso é curioso, já que long long int
é um inteiro assinado de 64 bits e é, para todos os efeitos, idêntico aos tipos long int
e int64_t
, então logicamente int64_t
, long int
e long long int
seriam tipos equivalentes - o assembly gerado ao usar esses tipos é idêntico. Uma olhada stdint.h
me diz por quê:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
Em uma 64 bits de compilação, int64_t
é long int
, não um long long int
(obviamente).
A solução para essa situação é muito fácil:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
Mas isso é terrivelmente hackeado e não se ajusta bem (funções reais da substância uint64_t
, etc.). Portanto, minha pergunta é: há uma maneira de dizer ao compilador que long long int
a também é a int64_t
, assim como long int
é?
Meu pensamento inicial é que isso não é possível, devido à maneira como as definições de tipo C / C ++ funcionam. Não há uma maneira de especificar a equivalência de tipo dos tipos de dados básicos para o compilador, uma vez que essa é a função do compilador (e permitir isso poderia quebrar muitas coisas) e typedef
só vai em um caminho.
Eu também não estou muito preocupado em obter uma resposta aqui, uma vez que este é um caso extremamente extremo que eu não suspeito que alguém se importará quando os exemplos não forem terrivelmente inventados (isso significa que deve ser um wiki da comunidade?) .
Anexo : O motivo pelo qual estou usando a especialização parcial de modelo em vez de um exemplo mais fácil como:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
é que o referido exemplo ainda será compilado, uma vez que long long int
é implicitamente conversível em um int64_t
.
Anexo : A única resposta até agora pressupõe que eu quero saber se um tipo é 64 bits. Não queria enganar as pessoas fazendo-as pensar que me importo com isso e provavelmente deveria ter fornecido mais exemplos de onde esse problema se manifesta.
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
Neste exemplo, some_type_trait<long int>
será um boost::true_type
, mas some_type_trait<long long int>
não será. Embora isso faça sentido na ideia de tipos do C ++, não é desejável.
Outro exemplo é usar um qualificador como same_type
(que é muito comum de usar em C ++ 0x Concepts):
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
Esse exemplo falha ao compilar, uma vez que C ++ (corretamente) vê que os tipos são diferentes. g ++ falhará ao compilar com um erro como: nenhuma chamada de função correspondente same_type(long int&, long long int&)
.
Gostaria de enfatizar que entendo por que isso está acontecendo, mas estou procurando uma solução que não me obrigue a repetir o código em todos os lugares.
sizeof
cada tipo? Talvez o compilador esteja tratando o tamanho de maneiralong long int
diferente.