c ++中的函数地址文字在哪里?

时间:2010-05-20 21:40:47

标签: c++ generics templates assembly

更新:经过一些额外的阅读后,我真正想要的是保证早期绑定(这应该转换为立即调用非虚函数和非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 {...};

并在my_template中调用func_literal编译为callq <immediate address>

C ++中是否有设施可以实现相同的效果?如果没有,为什么不(例如一些灾难性的副作用)? C ++ 0x或其他语言怎么样?

7 个答案:

答案 0 :(得分:3)

如果在模板中使用函数指针类型并使用固定函数对其进行实例化,则编译器应使用该函数指针调用的直接调用。

答案 1 :(得分:1)

CodeProject.com:

我在几个平台上使用过:http://www.codeproject.com/kb/cpp/FastDelegate.aspx

在搜索结果中看到,将显示为:http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx

......或者这不是你想要的东西吗?

答案 2 :(得分:1)

#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);                                                                    
}                                                                               

答案 3 :(得分:0)

在C ++语言中,翻译人员不会将函数名称折叠到可执行文件中,它们会丢失并永远消失。

您可以创建一个功能名称与功能地址的表格。由于C和C ++是类型信息的粘合剂,因此在汇编语言中可能更容易声明。在高级语言中,您必须为每种不同类型的函数指针创建一个表。但是,在装配中,它并不在乎。虽然您可以使用其中带有switch的函数来返回函数指针或执行函数。

另一种方法是功能ID(枚举)与功能地址。

答案 4 :(得分:0)

至少如果我理解你的问题,这是微不足道的:

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

func();的来电通常会在您询问时直接调用func(),或者如果func()很小,则其代码通常会内联生成。如果您想提高内联生成的机会,通常需要将其编写为仿函数(重载operator()的类)而不是正常函数。作为一个普通的函数,你最常会调用实际的函数(但它将是一个直接调用,而不是通过指针调用)。

编辑:我不确定我在想什么,但你说得对:这只适用于仿函数,而不是实际函数。道歉。

答案 5 :(得分:0)

以为我会分享我自己的标准功能解决方案,这里从其他答案扩展而来。这使用可变参数作为简写。作为一组N-ary模板来做这件事并不困难(只是单调乏味)。有趣的是,N-ary模板对于此模式更灵活,因为不再需要嵌套结构。使用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&gt; = 4.5和vs2008。

答案 6 :(得分:0)

也可以将函数引用传递给模板。这编译在最新的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();
}

我不确定与使用函数指针相比​​,这是否真的会有所不同。