在编译时将函数指针转换为std :: uintptr_t

时间:2019-06-19 01:06:14

标签: c++ templates constexpr

我想在编译时将常量表达式函数指针转换为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;
}

1 个答案:

答案 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>();