2010-06-02 2 views
2

Я знаю, что я могу передать указатель на функцию в качестве параметра шаблона и получить вызов ему встраиваемый, но я подумал, что какие-либо компиляторы эти дней могут INLINE в «очевидную» инлайн-возможности функции, как:C++ указатель Функции встраивание

inline static void Print() 
{ 
std::cout << "Hello\n"; 
} 

.... 

void (*func)() = Print; 

func(); 

В Visual Studio 2008 он достаточно умен, чтобы получить его до инструкции прямого вызова, поэтому кажется, что это позор, но он не может сделать шаг дальше?

+0

Вы уверены, что это не инструкция прямого вызова для 'ostream <<'? – James

+0

Plese отформатируйте свой код, используя кнопку '101010' в редакторе. – sbi

+0

Да, я проверил сборку. О форматировании кода я не знал, но теперь я делаю :) – iam

ответ

2

г проекта GNU ++ 4.5 встраивает это для меня, начиная с уровня -O1

main: 
    subq $8, %rsp 
    movl $6, %edx 
    movl $.LC0, %esi 
    movl $_ZSt4cout, %edi 
    call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_E 
    movl $0, %eax 
    addq $8, %rsp 
    ret 

оптимизации, где .LC0 является .String "Привет \ п".

Для сравнения, без оптимизации, г ++ -O0, он не встраивать:

main: 
    pushq %rbp 
    movq %rsp, %rbp 
    subq $16, %rsp 
    movq $_ZL5Printv, -8(%rbp) 
    movq -8(%rbp), %rax 
    call *%rax 
    movl $0, %eax 
    leave 
    ret 
+0

Отлично, что хорошо знать, поскольку существуют различные полезные конструкции, где это может привести к их нулевому результату. :) Позор, что Visual C++ еще не так умна! Спасибо. – iam

1

Ну, компилятор действительно не знает, будет ли эта переменная заменена где-то или нет (может быть, в другом потоке?), Поэтому она ошибается на стороне осторожности и реализует ее как вызов функции.

Я только что проверил в VS2010 в сборке релиза, и он не получил встроенного.

Кстати, вы украшаете функцию как inline бесполезно. В стандарте говорится, что если вы когда-либо получите адрес функции, любой намек inline будет проигнорирован.

Редактировать: обратите внимание, однако, что, хотя ваша функция не вставлена, переменная ушла. При разборке call использует прямой адрес, он не загружает переменную в регистр и вызывает это.

+1

Да, вот что Я подумал, что я просто попробовал __restrict на нем, а также const безрезультатно. Да, я пробовал встроенный и __forceinline, как вы никогда не знаете :) IE: void (* const __restrict func)() = Local :: Print; Я надеялся, что в VS2010 они могут возникнуть из-за лямбда и т. Д. - не изменит ли ситуация VS2010? – iam

+0

Нет, компилятор отказывается от встроенного, что немного странно, потому что, если оно устраняет переменную, тогда нет никакой опасности изменения переменной, поэтому она может просто заменить «вызов» на тело функции. О хорошо ... – Blindy

+0

компилятор не должен предполагать, что переменная может быть перезаписана в другом потоке. Если есть вероятность, что один и тот же поток может перезаписать переменную, компилятор должен играть в нее безопасно, но в простом случае, подобном показанному OP, также нет никакого риска (и именно поэтому он может устранить переменная). Компилятор * должен * иметь возможность встроить простой пример. – jalf

2

Новые выпуски GCC (4.4 и выше) имеют возможность с именем -findirect-встраивание. Если GCC может доказать себе, что указатель функции является постоянным, он делает прямой вызов функции или полностью строит функцию.

Смежные вопросы