Проверьте во время компиляции, имеет ли функция внешнюю связь - PullRequest
3 голосов
/ 25 июня 2019

Можно ли проверить во время компиляции, указывает ли указатель на функцию с внешней связью?

То, что я представляю себе, - это шаблон типа черт типа, который возвращает, имеет ли указатель функциивнешняя связь.

void linked() {}

void test() {
  // Returns true, since `linked` will have external linkage.
  bool fn = has_external_linkage<linked>::value;

  auto unlinked = []() {};
  constexpr auto *unlinked_ptr = +unlinked;

  // Returns false, since function pointers to lambdas
  // have no external linkage.
  bool lambda = has_external_linkage<unlinked_ptr>::value;
}

Обоснование

Что меня действительно волнует, так это то, допустимо ли передавать указатель функции в качестве параметра шаблона.Следующий код завершается ошибкой в ​​GCC, утверждая, что fn не имеет внешней связи.

template <typename FnType, FnType fn>
void call() {
  fn();
}

int main(int argc, char** argv) {
  auto lambda = []() {};
  constexpr *lambda_ptr = +lambda;
  call<decltype(lambda_ptr), lambda_ptr>();
  return 0;
}

Если я заменю lambda_ptr на указатель constexpr на обычную функцию, код скомпилируется нормально,так как функция будет иметь внешнюю связь.

По сути, я бы хотел избежать издержек во время выполнения при отправке указателя функции всякий раз, когда возможно закодировать его как параметр шаблона.Однако я все же хотел бы иметь возможность отправлять указатель на функцию, когда он не может быть параметром шаблона.Поэтому я хотел бы создать что-то вроде шаблона has_external_linkage, чтобы я мог выбрать подходящий путь.

1 Ответ

0 голосов
/ 25 июня 2019

ИМХО, использование адреса функции в качестве параметра шаблона - UB, и вы никогда не должны его использовать. Причина в том, что для разных компиляторов на разных платформах адрес функции может быть неизвестен с правами на время выполнения.

То, что он работает на архитектурах, в которых есть виртуальные машины и назначают статические виртуальные адреса локальным функциям, ничего не значит, поскольку UB позволяет работать любым способом, даже тем, который, как вы ожидаете, будет работать;)

Вместо этого, как было предложено в каком-то другом вопросе, вы можете передать объект функции по значению.

...