Где функциональные литералы адреса в C++?

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

6
задан academicRobot 11 June 2010 в 17:39
поделиться

6 ответов

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

3
ответ дан 17 December 2019 в 04:43
поделиться

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

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

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

0
ответ дан 17 December 2019 в 04:43
поделиться

CodeProject.com:

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

Увидел в результатах поиска: http://www.codeproject.com/KB/cpp/ImpossibleFastCppDelegate.aspx

... или это не то, что вы ищете?

1
ответ дан 17 December 2019 в 04:43
поделиться
#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
ответ дан 17 December 2019 в 04:43
поделиться

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

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

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

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

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

0
ответ дан 17 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: