Подтвердить что ты не робот

Почему ясно, что экземпляр функции шаблона не будет встроен?

Относительно Функция передана как аргумент шаблона, ответ сообщества wiki, предоставленный Беном Супником, обсуждает проблему встраивания созданных шаблонов функций.

В этом ответе приведен следующий код:

template<typename OP>
int do_op(int a, int b, OP op)
{
  return op(a,b,);
}

int add(int a, b) { return a + b; }

int (* func_ptr)(int, int) = add;

int c = do_op(4,5,func_ptr);

В ответе говорится (в отношении последней строки, которая создает экземпляр шаблона функции do_op):

ясно, что это не делается.

Мой вопрос таков: почему ясно, что это не делается встраиванием?

4b9b3361

Ответ 1

То, что он говорит (я думаю), заключается в том, что функция add не входит в состав. Другими словами, компилятор может встроить do_op следующим образом:

int c = func_ptr(4, 5);

но он не будет также inline add следующим образом:

int c = 4 + 5;

Однако он может ошибаться в этом простом примере.

Как правило, когда вы вызываете функцию через указатель, компилятор не может знать (во время компиляции), какую функцию вы будете вызывать, поэтому он не может встроить функцию. Пример:

void f1() { ... }
void f2() { ... }

void callThroughPointer() {
    int i = arc4random_uniform(2);
    void (*f)() = i ? f2 : f1;
    f();
}

Здесь компилятор не может знать, будет ли callThroughPointer вызывать f1 или f2, поэтому нет возможности встраивать либо f1, либо f2 в callThroughPointer.

Однако, если компилятор может во время компиляции доказать, какая функция будет вызываться, разрешается встроить функцию. Пример:

void f1() { ... }
void f2() { ... }

void callThroughPointer2() {
    int i = arc4random_uniform(2);
    void (*f)() = i ? f2 : f1;
    f = f1;
    f();
}

Здесь компилятор может доказать, что f всегда будет f1, поэтому ему разрешено встраивать f1 в callThroughPointer2. (Это не значит, что он будет inline f1...)

Аналогично, в примере, который вы цитировали в своем сообщении, компилятор может доказать, что func_ptr всегда add в вызове do_op, поэтому ему разрешено встроить add. (Это не значит, что он будет inline add...)

Ответ 2

При вызове функции через указатель функции компилятор вряд ли избежит вызова через указатель функции. Только если компилятор может доказать, что он знает, что инициализируется указателем на функцию, и что его нельзя изменить, он мог бы избежать вызова функции через указатель функции и, таким образом, встроить функцию. В цитированной настройке, то есть

int (* func_ptr)(int, int) = add;

указатель функции func_ptr может быть изменен, поэтому компилятор не гарантирует, что он никогда не изменится. В результате он не может включить вызов add.

Если фрагмент кода действительно завершен, все происходит во время инициализации, и компилятор действительно может действительно знать, что func_ptr инициализируется, чтобы содержать add.

Ответ 3

Почему ясно, что это не встраивается?

Это не так. Там нет причин, по которым компилятор не мог встроить весь код в этот фрагмент.