É possível passar o endereço do primeiro elemento de um array como argumento para std::bit_cast
.
#include <bit>
#include <iostream>
struct A {
int a;
int b;
int c;
int d;
int e;
void print() {
std::cout << a << ", " << b << ", " << c << ", " << d << ", " << e << std::endl;
}
};
int main() {
char arr[20]{};
// arr is filled with some data
A a = std::bit_cast<A>(arr);
a.print();
const char* arrp = arr;
// doesn't compile
A b = std::bit_cast<A>(arrp);
b.print();
}
Erro
<source>: In function 'int main()':
<source>:23:27: error: no matching function for call to 'bit_cast<A>(const char*&)'
23 | A b = std::bit_cast<A>(arrp);
| ~~~~~~~~~~~~~~~~^~~~~~
In file included from <source>:1:
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bit:81:5: note: candidate: 'template<class _To, class _From> constexpr _To std::bit_cast(const _From&) requires sizeof (_To) == sizeof (_From) && __is_trivially_copyable(_To) && __is_trivially_copyable(_From)'
81 | bit_cast(const _From& __from) noexcept
| ^~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bit:81:5: note: template argument deduction/substitution failed:
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bit:81:5: note: constraints not satisfied
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bit: In substitution of 'template<class _To, class _From> constexpr _To std::bit_cast(const _From&) requires sizeof (_To) == sizeof (_From) && __is_trivially_copyable(_To) && __is_trivially_copyable(_From) [with _To = A; _From = const char*]':
<source>:23:27: required from here
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bit:81:5: required by the constraints of 'template<class _To, class _From> constexpr _To std::bit_cast(const _From&) requires sizeof (_To) == sizeof (_From) && __is_trivially_copyable(_To) && __is_trivially_copyable(_From)'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bit:83:27: note: the expression 'sizeof (_To) == sizeof (_From) [with _To = A; _From = const char*]' evaluated to 'false'
83 | requires (sizeof(_To) == sizeof(_From))
| ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
Compiler returned: 1
Matrizes não são ponteiros.
std::bit_cast<A>(arr);
está correto.arr
é passado por referência, e porstd::bit_cast
ter umconst From&
parâmetro,From
deduzchar[20]
e você está efetivamente passandoconst char(&)[20]
, ou seja, "referência ao array de 20const char
". Isso não é o mesmo que passar um ponteiro.Por outro lado,
std::bit_cast<A>(arrp);
tenta converter um ponteiro em bits (com size8
, presumivelmente) para umA
(com size20
, presumivelmente), e você não pode converter bits entre tipos de tamanhos diferentes.A melhor abordagem aqui é digitar trocadilhos
std::memcpy
, o que funciona porqueA
é trivialmente copiável e tem vida útil implícita:Consulte também Qual é a maneira moderna e correta de digitar trocadilhos em C++?
An
array
pode decair para um ponteiro em algum contexto, mas neste caso isso não acontece. Em vez disso, ele permanece como um bloco de memóriaarray
estd::bit_cast
pode pegar seu endereço e tratá-lo como um bloco contíguo de memória. [1]No segundo caso,
arrp
é um ponteiro. Quando você passaarrp
parastd::bit_cast
, você está passando um ponteiro, não um bloco de memória. Esta é uma distinção importante. Se você observar a possível implementação sugerida destd::bit_cast
[cppreference] de acordo com cppreference, ela sugere que o endereço do argumento da função será eventualmente obtido e passado como um argumento parastd::memcpy
:Veja o problema agora? O argumento do ponteiro é inesperado porque ainda levará o endereço de
src
. Você pode usar o núcleo da implementação diretamente, sem todas as verificações.Obrigatório: você percebe que está indo para um nível muito baixo agora e um monte de coisas não são confiáveis. Por exemplo,
int
pode não ter exatamente 32 bits. A afirmação quesizeof struct A == sizeof char arr[20]
não é garantida em todas as implementações.[1] Não decai porque é passado
const&