我想实现一个返回默认值的通用函数,然后通过函数指针使用它来替换具有不同原型的其他函数。
例如:
int replacement() {
return 43;
}
int (*abstract)(int i, const char *c);
int main() {
abstract = reinterpret_cast<decltype(abstract)>(replacement);
int res = (*abstract)(55, "Test");
std::cout << "Result is " << res << std::endl;
}
这段代码有效,并且实际上达到了我的预期,但根据标准,它是未定义的行为。或者是吗?
我可以依靠 ABI 来做正确的事吗?参数是在寄存器中传递或压入堆栈的,那么如果不使用它们,应该没有问题。例如,在 GTK+ 和 Vulkan 中使用
reinterpret_cast
或其他等效的强制转换来将通用函数类型作为指针传递,并让开发人员在另一端取消强制转换正确的函数类型。
这只是偶然发生的,还是我可以依赖这种行为?
它的工作纯属偶然。你永远不能依赖未定义的行为。
.
int stub() { return 42; }
int real(int i) { return i * 2; }
void foo(bool active) {
int (*ptr)(int);
if (active) {
ptr = ℜ
} else {
ptr = reinterpret_cast<int (*)(int)>(&stub);
}
int arg = ptr(99);
if (active) {
submit_request(arg);
}
}
编译器可以看到
active == false
导致 UB,因此在 foo
始终存在的假设下优化 active == true
。
(我尝试过的编译器都没有这样做,但这仅意味着他们还没有费心添加这样的优化还。)
您应该这样做:可变参数模板可让您为您需要的任何签名定义存根:
#include <cstdio>
void submit_request(int);
template <typename... Args>
int stub(Args...) {
std::printf("stub");
return 42;
}
int real(int i) { return i * 2; }
void foo(bool active) {
int (*ptr)(int);
if (active) {
ptr = ℜ
} else {
ptr = static_cast<int (*)(int)>(&stub);
}
int arg = ptr(99);
if (active) {
submit_request(arg);
}
}