Преобразовать указатель функции в std :: uintptr_t во время компиляции - PullRequest
1 голос
/ 19 июня 2019

Я хотел бы преобразовать указатель функции константного выражения в 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 Ответ

4 голосов
/ 19 июня 2019

Тем не менее, я понимаю, что std :: uintptr_t должен содержать любой тип указателя, а это означает, что это можно сделать в константном выражении.

Конечно. Но reinterpret_cast никогда не допускается в постоянном выражении. И поскольку это единственный способ преобразовать указатель в целое число, это не то, что вы можете сделать во время компиляции .

Если вы хотите передать указатель на функцию в качестве параметра шаблона, тогда просто сделайте это :

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>();
...