ОБНОВЛЕНИЕ: После некоторого дополнительного чтения, что я действительно хотел, гарантировался раннее связывание (который должен переведенный в непосредственный призыв к невиртуальным функциям и коду не-PIC), который может быть сделан путем передачи (участник) функции как шаблонного параметра. Проблема, которую я имел, состояла в том, что gcc <4.5 и icc 11.1 может генерировать некоторые броские инструкции для шаблонных вызовов параметра указателя функции членства. AFAICT, gcc> = 4,5 и vs2008 обрабатывают эти шаблонные прекрасные вызовы параметра.
В первую очередь, возможно, литералы не являются правильным словом для этого понятия, но это является самым близким, я мог думать (не литералы в смысле функций как граждане первого класса).
Идея состоит в том, что при создании стандартного вызова функции он компилирует во что-то вроде этого:
callq <immediate address>
Но если Вы делаете вызов функции с помощью указателя функции, он компилирует во что-то вроде этого:
mov <memory location>,%rax
callq *%rax
Который является всем хорошо и хороший. Однако, что, если я пишу библиотеку шаблонов, которая требует, какой-то обратный вызов с указанным списком аргументов и пользователем библиотеки, как ожидают, будет знать то, что функционирует, они хотят звонить во время компиляции? Затем я хотел бы записать свой шаблон для принятия функционального литерала как шаблонный параметр. Так, подобный
template <int int_literal>
struct my_template {...};`
Я хотел бы записать
template <func_literal_t func_literal>
struct my_template {...};
и имейте вызовы к func_literal в компиляции my_template к callq <immediate address>
.
Существует ли средство в C++ для этого или работа вокруг для достижения того же эффекта? В противном случае, почему не (например, некоторые катастрофические побочные эффекты)? Как насчет C++ 0x или другой язык?
Если вы используете тип указателя функции в вашем шаблоне и инстанцируете его с фиксированной функцией, то компилятор должен использовать прямой вызов для вызова указателя функции.
В языке C ++ переводчики не складывают имена функций в исполняемый файл, они теряются и исчезают навсегда.
Вы можете составить таблицу названия функции по сравнению с адресом функции. Поскольку C и C ++ являются приверженцами информации о типах, это может быть проще объявить на языке ассемблера. На языке высокого уровня вам потребуется таблица для каждого типа указателя на функцию. Однако в сборке это не волнует. Хотя вы можете использовать функцию с переключателем
, чтобы вернуть указатель на функцию или выполнить функцию.
Альтернативой являются идентификаторы функций (перечисления) вместо адресов функций.
CodeProject.com:
Я использовал на нескольких платформах: http://www.codeproject.com/kb/cpp/FastDelegate.aspx
Увидел в результатах поиска: http://www.codeproject.com/KB/cpp/ImpossibleFastCppDelegate.aspx
... или это не то, что вы ищете?
#include <iostream>
template<void F()>
struct CALLER
{
static void do_call()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
F();
};
};
void f()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
CALLER<f>::do_call();
return(0);
}
Думал, что поделюсь своим собственным решением для стандартных функций, расширенным из других ответов здесь. Здесь для краткости используются вариативные параметры. Это было бы несложно (просто утомительно) сделать как набор N-арных шаблонов. Интересно, что N-арные шаблоны более гибки для этого шаблона, поскольку вложенная структура больше не потребуется. Компилируется с помощью g ++ -std = c ++ 0x
template <typename F>
struct caller;
template <class R, class ... A>
struct caller<R(A ...)>{
template <R F(A ...)>
struct func{
R operator()(A ... args){
return F(args ...);
}
};
};
, который вызывается и вызывается следующим образом:
int echoFunc(int i) {std::cout << "echo " << i << std::endl; return i;}
...
caller<int(int)>::func<echoFunc> f;
f(1);
Без -O2
компилируется в два вложенных немедленных вызова функций с -O2
вызов f (1)
сводится к немедленному вызову echoFunc
.
Это работает, как и ожидалось, для функций-членов с gcc> = 4.5 и vs2008.
По крайней мере, если я правильно понимаю ваш вопрос, это тривиально:
template <class func>
struct whatever {
operator()() {
func();
}
};
Вызов func ();
обычно заканчивается прямым вызовом func ()
, как вы просили, или если func ( )
небольшой, его код часто генерируется встроенным. Если вы хотите повысить шансы того, что он будет сгенерирован встроенным, вы обычно хотите написать его как функтор (класс, который перегружает operator ()
) вместо нормальной функции. Как обычная функция, вы чаще будете вызывать фактическую функцию (но это будет прямой вызов, а не вызов через указатель).
Edit: Я не уверен, о чем я думал, но вы совершенно правы: это будет работать только с функтором, а не с реальной функцией. Мои извенения.