Как проверить во время компиляции, если вызвана функция

Я пытаюсь определить во время компиляции, вызвана ли функция. В частности, я хочу сбросить статическое утверждение, если оно:

template <typename T>
auto Function(T value) -> std::enable_if<someCondition, int>
{
  // this is the function I want to call
}

template <typename... T>
int Function(T...)
{
  // This function should never be called, instead I want
  // a compile-time failure if this is called, because it
  // means the above function wasn't successfully resolved.
}

Причина, по которой я хочу сделать это, состоит в том, что неудача для корректного вызова Function() с правильными условиями приводит к тысячам строк сообщений об ошибках компилятора, ни одна из которых не очень помогает никому, кто не знаком с базой кода.

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

Можно ли это сделать?

Ответ 1

На основе комментариев по вашему вопросу вы не хотите static_assert здесь:

template <typename T>
auto Function(T value) -> std::enable_if<someCondition, int>
{
  // this is the function I want to call
}

... но здесь нет ничего плохого в static_assert здесь:

template <typename... T>
struct dependent_false { static constexpr bool value = false; };

template <typename... T>
int Function(T...)
{
  static_assert(dependent_false<T...>::value, "you are passing the wrong arguments!");
}

Как вы правильно отметили, простой static_assert(false, "..."); завершится неудачей во время определения шаблона. Чтобы получить то, что только не выполняется во время создания экземпляра, вам нужно зависимое выражение, а вспомогательная структура dependent_false - это простой способ получить то, что будет зависящим от типа, будет всегда всегда false, но не может быть принято компилятором по-настоящему всегда быть false: компилятор не может исключить добавление частичных специализаций для создания dependent_false<...>::value true для некоторого типа.


Оглядываясь назад на этот старый вопрос, может быть гораздо более простой ответ: отметьте перегрузку как удаленную.

template <typename T>
auto Function(T value) -> std::enable_if<someCondition, int>
{
    // this is the function I want to call
}

template <typename... T>
int Function(T...) = delete;

Это не совсем то же самое, поскольку это позволяет вызывающему лицу проверить правильность формы, например. Function(int, int) вместо того, чтобы вызывать ошибку, но это более читаемо, и обычно вам нужно, чтобы точное поведение не получало ошибку, если функция фактически не используется, а не просто ссылается.