Вы также можете получить хорошее представление о том, что будет делать компилятор, используя ассемблер вашего компилятора или что-то вроде этой онлайн-утилиты: https://godbolt.org и взглянув на полученный код сборки.
Это стоило посмотреть, так как вопрос является фундаментальным.
Пример, основанный на вашем вопросе, при рассмотрении примитивов и "сложных" (даже не очень) с учетом объявления и создания локальных и статических типов:
#include <iostream>
struct non_primitive
{
int v;
non_primitive(const int v_) : v(v_) {}
};
void test_non_static_const_primitive()
{
const int ABC = 12;
std::cout << ABC;
}
void test_static_const_primitive()
{
const static int ABC = 12;
std::cout << ABC;
}
void test_non_static_constant_non_primitive_global_struct()
{
const non_primitive s(12);
std::cout << s.v;
}
void test_non_static_constant_non_primitive_local_struct()
{
struct local_non_primitive
{
int v;
local_non_primitive(const int v_) : v(v_) {}
};
const local_non_primitive s(12);
std::cout << s.v;
}
void test_static_constant_non_primitive_global_struct()
{
const static non_primitive s(12);
std::cout << s.v;
}
void test_static_constant_non_primitive_local_struct()
{
struct local_non_primitive
{
int v;
local_non_primitive(const int v_) : v(v_) {}
};
const static local_non_primitive s(12);
std::cout << s.v;
}
Компилятор признает, что ему не нужно иметь дело с каким-либо связыванием памяти для локальных сложных типов const, и первые четыре случая обрабатываются одинаково. Похоже, что компилятор не пытается исследовать относительную простоту сложного типа и потенциал для дальнейшего упрощения в статической реализации.
Полученная разница в стоимости относительно велика.
Скомпилированный код сборки с использованием gcc7.2 с оптимизацией -O3:
test_non_static_const_primitive():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_static_const_primitive():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_non_static_constant_non_primitive_global_struct():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_non_static_constant_non_primitive_local_struct():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_static_constant_non_primitive_global_struct():
movzx eax, BYTE PTR guard variable for test_static_constant_non_primitive_global_struct()::s[rip]
test al, al
je .L7
mov esi, DWORD PTR test_static_constant_non_primitive_global_struct()::s[rip]
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
.L7:
sub rsp, 8
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_global_struct()::s
call __cxa_guard_acquire
test eax, eax
mov esi, DWORD PTR test_static_constant_non_primitive_global_struct()::s[rip]
je .L8
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_global_struct()::s
mov DWORD PTR test_static_constant_non_primitive_global_struct()::s[rip], 12
call __cxa_guard_release
mov esi, 12
.L8:
mov edi, OFFSET FLAT:std::cout
add rsp, 8
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_static_constant_non_primitive_local_struct():
movzx eax, BYTE PTR guard variable for test_static_constant_non_primitive_local_struct()::s[rip]
test al, al
je .L14
mov esi, DWORD PTR test_static_constant_non_primitive_local_struct()::s[rip]
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
.L14:
sub rsp, 8
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_local_struct()::s
call __cxa_guard_acquire
test eax, eax
mov esi, DWORD PTR test_static_constant_non_primitive_local_struct()::s[rip]
je .L15
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_local_struct()::s
mov DWORD PTR test_static_constant_non_primitive_local_struct()::s[rip], 12
call __cxa_guard_release
mov esi, 12
.L15:
mov edi, OFFSET FLAT:std::cout
add rsp, 8
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
_GLOBAL__sub_I__Z31test_non_static_const_primitivev:
sub rsp, 8
mov edi, OFFSET FLAT:std::__ioinit
call std::ios_base::Init::Init()
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:std::__ioinit
mov edi, OFFSET FLAT:std::ios_base::Init::~Init()
add rsp, 8
jmp __cxa_atexit