我想在编译时将常量表达式函数指针转换为std::uintptr_t
。我该怎么办?
这是一个最小的例子:
#include <cstdint>
void fn() {}
int main(int argc, char** argv) {
constexpr void* ptr = (void *) fn;
constexpr std::uintptr_t idx = reinterpret_cast<std::uintptr_t>(fn);
return 0;
}
GCC 7/8/9当前给我错误“在常量表达式中从指针类型转换为算术类型std::uintptr_t
”。但是,我的理解是std::uintptr_t
应该能够容纳任何指针类型,这意味着它应该能够在常量表达式中完成。
背景
要给我一些背景信息,我想要(1)在编译时获取函数指针的地址,(2)将其转换为std::uintptr_t
,然后(3)将其作为模板参数传递,以便可以在编译时将其烘焙到函数中。
这应该是RPC引擎的一部分,类似于此代码,它会产生非常类似的错误:
#include <cstdio>
#include <cstdint>
template <std::uintptr_t FnPtr, typename Fn>
void fn_handler() {
((Fn *) FnPtr)();
}
int main(int argc, char** argv) {
auto lel = []() {
printf("Hi, fam!\n");
};
// Note that +lel is an implement 0+lel, converting
// the lambda to a fn ptr.
constexpr void* ptr = reinterpret_cast<void*>(+lel);
constexpr std::uintptr_t idx = reinterpret_cast<std::uintptr_t>(ptr);
fn_handler<idx, decltype(lel)>();
return 0;
}
答案 0 :(得分:4)
但是,我的理解是std :: uintptr_t应该能够保存任何指针类型,这意味着它应该能够在常量表达式中完成。
好的。但是在常量表达式中,永远不允许reinterpret_cast
。而且因为这是将指针转换为整数的唯一方法,所以您不能在编译时
如果要将函数指针作为模板参数传递,则just do that:
int func() {return 0;}
template<int (*pfn)()>
int fn_handler()
{
return pfn();
}
...
fn_handler<&func>();
如果要将函数的类型设为模板参数,然后在C ++ 17之前,则可以使用类似以下的老技巧:
template<typename Fn, Fn pfn>
decltype(auto) fn_handler()
{
return pfn();
}
...
fn_handler<decltype(&func), &func>();
C ++ 17让我们仅使用auto
:
template<auto pfn>
decltype(auto) fn_handler()
{
return pfn();
}
...
fn_handler<&func>();