Где литералы адреса функции в c ++? - PullRequest
6 голосов
/ 21 мая 2010

ОБНОВЛЕНИЕ: После некоторого дополнительного чтения я действительно хотел получить раннее связывание (которое должно быть переведено в немедленный вызов для не виртуальных функций и кода не-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 или другого языка?

Ответы [ 7 ]

3 голосов
/ 21 мая 2010

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

1 голос
/ 21 мая 2010
#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);                                                                    
}                                                                               
1 голос
/ 21 мая 2010

CodeProject.com:

Я использовал на нескольких платформах: http://www.codeproject.com/kb/cpp/FastDelegate.aspx

Видел в результатах поиска, будет читать: http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx

... или это не та вещь, которую вы ищете?

0 голосов
/ 05 июля 2012

Также возможно передать ссылку на функцию в шаблон. Это компилируется в последнем clang (3.2) и выводит "Hello World!" как и следовало ожидать:

template<void(& f)()> struct test {
    void operator()() {
        f();
    }
};
void foo() {
    std::cout << "Hello World!\n";
}
test<foo> bar;
int main() {
    bar();
}

Я не уверен, что это действительно изменит ситуацию по сравнению с использованием указателя на функцию.

0 голосов
/ 23 мая 2010

Думаю, я поделюсь своим собственным решением для стандартных функций, расширенным из других ответов здесь.Это использует переменные параметры в качестве короткой руки.Было бы не сложно (просто утомительно) сделать это как набор 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.

0 голосов
/ 21 мая 2010

По крайней мере, если я правильно понимаю ваш вопрос, это тривиально:

template <class func>
struct whatever { 
    operator()() { 
        func();
    }
};

Вызов func(); обычно заканчивается прямым вызовом func(), как вы и просили, или, если func() мало, его код часто генерируется встроенным. Если вы хотите повысить шансы на его генерацию встроенным, вы, как правило, хотите записать его как функтор (класс, который перегружает operator()) вместо обычной функции. Как обычная функция, вы чаще будете вызывать реальную функцию (но это будет прямой вызов, а не вызов через указатель).

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

0 голосов
/ 21 мая 2010

В языке C ++ переводчики не складывают имена функций в исполняемый файл, они теряются и исчезают навсегда.

Вы можете составить таблицу имени функции в зависимости от адреса функции. Так как C и C ++ являются сторонниками информации о типе, это может быть легче объявлено на ассемблере. На языке высокого уровня вам потребуется таблица для каждого типа указателя на функцию. Однако при сборке это не волнует. Хотя вы можете использовать функцию с switch, чтобы вернуть указатель на функцию или выполнить функцию.

Альтернативой являются идентификаторы функций (перечисления) в сравнении с адресами функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...