Ответ 1
Некоторые хорошие материалы для чтения по этому поводу - Скотт Adams Эффективный С++ Майерса (третье издание). Пункт 30: Понимать все входы и выходы, где он утверждает, что вызов функционального указателя никогда не привязан, Третье издание было опубликовано в 2008 году, и я действительно смог получить gcc для встроенного вызова функции с помощью команды compile-time-constant-pointer, начиная с gcc 4.6, которая вышла в 2011 году (может быть, 2010?). Однако это было на C и сложно. В одном из сценариев мне пришлось объявить вызывающую функцию __attribute__((flatten))
, прежде чем она введет вызов (в этой ситуации я передал указатель функции как член структуры, указатель которой затем передал встроенной функции, которая сделала бы вызов функции указателем, который получил встроенный).
Короче говоря, нет, это не ошибка gcc, но это не означает, что gcc (и/или другие компиляторы), возможно, не смогут вставить это в какой-то день. Но реальная проблема, я думаю, заключается в том, что вы не понимаете, что на самом деле происходит здесь. Чтобы понять это, вы должны думать больше как программист по сборке или программист компилятора.
Вы передаете объект типа F<X>
и инициализируете его указателем на функцию-член другого класса. Вы не указали свой экземпляр объекта F<X>
, он Func f_
член как константа, а ваш член void F::operator()(T& t)
как константа. На уровне языка С++ компилятор должен рассматривать его как непостоянный. Это все еще не означает, что на этапе оптимизации не может быть установлено, что ваш указатель функции не изменяется, но вы делаете его невероятно тяжелым на данный момент. Но, по крайней мере, это локальный. Если ваш объект F<X>
был глобальным и не был объявлен static
, он запретил бы его полностью считать постоянным.
Надеюсь, вы делаете это при упражнении с инкрустацией указателем на функцию, а не как реальное решение для косвенности. Когда вы хотите, чтобы С++ создавал реальную производительность, вы используете силу типов. В частности, когда я объявляю параметр шаблона в качестве указателя функции-члена, это не просто константа, это часть типа. Я никогда не видел случая, когда этот метод генерирует вызов функции.
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
template <typename T, void (T::*f_)()>
class F {
public:
void operator()(T& t) {
(t.*f_)();
}
};
struct X {
X() : x_(0) {}
void f(){
++x_;
}
int x_;
};
int __attribute__((flatten)) main()
{
const int N = 100000000;
vector<X> xv(N);
auto begin = clock();
for_each (xv.begin(), xv.end(), F<X, &X::f>());
auto end = clock();
cout << end - begin << endl;
}