2011-10-13 119 views
1

以下是否会导致明确的行为?也就是说,如果您将非可变参数函数f作为可变参数函数g并使用f期望的参数调用g,那么行为是否与使用这些参数调用f的行为相匹配?C++可变参数函数指针

class Base {}; 

class Derived1 : public Base { 
public: 
    int getInt1() {return 1;} 
}; 

class Derived2 : public Base { 
public: 
    int getInt2() {return 2;} 
}; 

typedef int (*vfunc)(...); 

int foo (vfunc f) { 
    Derived1 d1; 
    Derived2 d2; 
    return f(&d1, &d2); 
} 

int bar (Derived1 * p1, Derived2 * p2) { 
    return p1->getInt1() + p2->getInt2(); 
} 

int main (int argc, char ** argv) { 
    return foo((vfunc)bar); // Is this program guaranteed to return 3? 
} 

UPDATE

有一些办法可以让程序得到很好的界定,即使使用专有的关键字?比如做喜欢这里提到的__cdecl一些东西:

http://msdn.microsoft.com/en-us/library/984x0h58%28v=vs.80%29.aspx

我的最终目标是拥有一个matcher功能,试图X指针的列表匹配。匹配器函数接受一个谓词(不一定是一个函数...可能是一个列表),并接受一个函数,它会将匹配的结果传递给它。传递给它的回调函数采用与谓词匹配相同的参数类型和参数。

+0

我相信并期待答案是这是未定义的行为。 –

+0

当你说“专有关键字”时,你是什么意思?您定位的是什么编译器(以及版本和设置)?你打开其他更好的解决方案(如'std :: function')吗? –

+0

像Visual Studio中的__cdecl一样的东西。我也开放其他解决方案。 –

回答

6

否,该行为是未定义,每C++ 11 5.2.11/6(reinterpret_cast):

通过一个指向函数类型调用函数的作用是不一样的在函数的定义中使用的类型是未定义的。

bar的类型是int(Derived1*, Derived2*)。由f指向的函数的类型(通过其进行调用的表达式)是int(...)。两者不一样,因此行为未定义。

+0

你能解释一下这个例子中使用的函数的语言连接吗? –

+0

@ K-ballo:道歉;复制和粘贴是我遇到麻烦的技巧。我已更正引用。 –

2

我很肯定答案是“不”。例如,在Visual C++中,可变参数函数将具有与正常函数不同的调用约定(当使用/Gz时)。

调用约定决定生成预调用和调用后汇编代码,并且不能安全地混合这两者。

+0

如果一个人将调用约定指定为“cdecl”,那该怎么办? –

+0

@ K-ballo:你可能会很幸运,但它依赖于实现。我不相信C++中有任何规则说编译器必须为您提供一种自己指定调用约定的方法。实际上,C++标准对调用约定的含义很少。 (这意味着*假设最糟糕的:) – jwd