在编译时将函数指针转换为 std::uintptr_t
Convert function pointer to std::uintptr_t at compile time
我想在编译时将常量表达式函数指针转换为 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 目前给我错误 "conversion from pointer type to arithmetic type std::uintptr_t
in a constant expression." 然而,我的理解是 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;
}
However, my understanding was that std::uintptr_t should be able to hold any pointer type, meaning this should be able to be done in a constant expression.
当然可以。但是 reinterpret_cast
是 never 常量表达式中允许的。由于这是将指针转换为整数的唯一方法,因此您无法在编译时。
如果你想传递一个函数指针作为模板参数,那么just do that:
int func() {return 0;}
template<int (*pfn)()>
int fn_handler()
{
return pfn();
}
...
fn_handler<&func>();
如果你想让函数的类型成为模板参数,那么pre-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>();
我想在编译时将常量表达式函数指针转换为 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 目前给我错误 "conversion from pointer type to arithmetic type std::uintptr_t
in a constant expression." 然而,我的理解是 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;
}
However, my understanding was that std::uintptr_t should be able to hold any pointer type, meaning this should be able to be done in a constant expression.
当然可以。但是 reinterpret_cast
是 never 常量表达式中允许的。由于这是将指针转换为整数的唯一方法,因此您无法在编译时。
如果你想传递一个函数指针作为模板参数,那么just do that:
int func() {return 0;}
template<int (*pfn)()>
int fn_handler()
{
return pfn();
}
...
fn_handler<&func>();
如果你想让函数的类型成为模板参数,那么pre-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>();