хорошо
Во-первых, как вы заметили, глобальный оптимизатор генерирует одинаковый полностью встроенный код для обоих вариантов :
mov DWORD PTR [rsp-8], 2
mov eax, DWORD PTR [rsp-8]
imul eax, eax
mov DWORD PTR [rsp-4], eax
В шаблонной версии вам больше ничего не нужно, поскольку больше ничего нельзя вызвать из другого модуля компиляции.
Плохой; -)
Теперь ваша функциональная версия o2()
имеет внешнюю связь . Таким образом, он может быть вызван из другого блока перевода, если вы свяжете его с тем, который будет ссылаться на него. Вот почему вызываемый код для функции также генерируется под меткой o2(std::function<int (int)>, int)
и сохраняется, несмотря на то, что он не нужен «встроенному» коду.
И безобразный
В функциональном варианте есть еще какой-то дополнительный код, который менее очевиден. Если присмотреться повнимательнее, я предполагаю, что используемая реализация std::function
создает экземпляры некоторых классов (возможно, с использованием CRTP), которые представляют лямбду как вызываемый класс:
- функция-член, которая реализует лямбду таким образом, чтобы она вызывалась как функция-член (типичный подход для создания вызываемого объекта) под меткой
std::_Function_handler<int (int), main::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&):
- функция-член, которая реализует некоторый код котельной пластины для вызова предыдущего под меткой
std::_Function_base::_Base_manager<main::{lambda(int)#1}>::_M_manager(std::_Any_data&, std::_Function_base::_Base_manager<main::{lambda(int)#1}> const&, std::_Manager_operation):
- некоторые
typeinfo
и виртуальный стол. Это показывает, что хотя бы один из этих классов является полиморфным.
- некоторый код для исключения (поскольку
function
может выдать)
Я полагаю, что по крайней мере один из этих классов имеет внешнюю связь , требующую от компилятора сохранять код функций-членов на случай, если на него можно будет ссылаться из другого модуля перевода.