Да.
Современные компиляторы используют «статическое одиночное назначение» (SSA) в качестве прохода оптимизации.
Каждый раз, когда вы присваиваете значение или изменяете его, создается концептуально другое значение. Иногда эти концептуально разные значения разделяют идентичность (для целей указателей).
Идентичность, когда вы берете адрес чего-либо, это то, что мешает этому.
Простые ссылки превращаются в псевдонимы для значения, на которое они ссылаются; у них нет идентичности. Это часть первоначального замысла проекта для ссылок, и поэтому у вас не может быть указателя на ссылку.
В частности:
std::string printSomeNumbers(void)
{
std::ostringstream ss;
const auto appendNumber = [&ss](auto number) {
ss << number << "\n"; // Pretend this is something non-trivial
};
printf("hello\n");
appendNumber(1);
printf("world\n");
appendNumber(2.0);
printf("today\n");
return ss.str();
}
компилируется в:
printSomeNumbers[abi:cxx11](): # @printSomeNumbers[abi:cxx11]()
push r14
push rbx
sub rsp, 376
mov r14, rdi
mov rbx, rsp
mov rdi, rbx
mov esi, 16
call std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::basic_ostringstream(std::_Ios_Openmode)
mov edi, offset .Lstr
call puts
mov rdi, rbx
mov esi, 1
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov esi, offset .L.str.3
mov edx, 1
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
mov edi, offset .Lstr.8
call puts
mov rdi, rsp
movsd xmm0, qword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero
call std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
mov esi, offset .L.str.3
mov edx, 1
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
mov edi, offset .Lstr.9
call puts
lea rsi, [rsp + 8]
mov rdi, r14
call std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const
mov rax, qword ptr [rip + VTT for std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >]
mov qword ptr [rsp], rax
mov rcx, qword ptr [rip + VTT for std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >+24]
mov rax, qword ptr [rax - 24]
mov qword ptr [rsp + rax], rcx
mov qword ptr [rsp + 8], offset vtable for std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >+16
mov rdi, qword ptr [rsp + 80]
lea rax, [rsp + 96]
cmp rdi, rax
je .LBB0_7
call operator delete(void*)
.LBB0_7:
mov qword ptr [rsp + 8], offset vtable for std::basic_streambuf<char, std::char_traits<char> >+16
lea rdi, [rsp + 64]
call std::locale::~locale() [complete object destructor]
lea rdi, [rsp + 112]
call std::ios_base::~ios_base() [base object destructor]
mov rax, r14
add rsp, 376
pop rbx
pop r14
ret
Godbolt
Обратите внимание, что между вызовами printf (в сборке они puts
) нет вызова, кроме прямого вызова operator<<
из ostringstream
.