以下是否会产生明确定义的行为?也就是说,如果你将非vararg函数f作为vararg函数g并使用f期望的参数调用g,那么行为是否与用这些参数调用f的行为相匹配?
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?
}
更新
即使使用专有关键字,是否有某些方法可以让程序定义明确?比如做一些像__cdecl
这样提到的东西:
http://msdn.microsoft.com/en-us/library/984x0h58%28v=vs.80%29.aspx
我的最终目标是使用matcher
函数尝试匹配X指针列表。 matcher函数接受一个谓词(不一定是函数......可能是一个列表),并接受一个函数,它将匹配的结果传递给。传递给它的回调函数采用与谓词匹配相同的参数类型和arity。
答案 0 :(得分:6)
不,根据C ++ 11 5.2.11 / 6(reinterpret_cast
),行为未定义:
通过指向与函数定义中使用的类型不同的函数类型的指针调用函数的效果是未定义的。
bar
的类型为int(Derived1*, Derived2*)
。 f
指向的函数类型(通过其进行调用的表达式)是int(...)
。两者不一样,因此行为未定义。
答案 1 :(得分:2)
我很确定答案是“不”。
例如,在Visual C ++中,可变参数函数将具有与普通函数不同的调用约定(使用/Gz
时)。
调用约定决定了生成的调用前和调用后汇编代码,并且您无法安全地混合这两个代码。