Есть ли способ использовать SFINAE, чтобы определить, не объявлена ​​ли не шаблонная функция, не являющаяся членом?

Я пытаюсь ответить на этот вопрос, используя SFINAE и decltype. Подводя итог, автор должен получить функцию, которая действует по-разному в зависимости от того, объявлена ​​ли другая функция в модуле компиляции (будь то объявлена ​​раньше или позже, чем рассматриваемая функция).

Я попробовал следующее:

auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {
    cout << "Using some_function_1" << endl;
    some_function_1();
}

void some_function_2_impl(long) {
    cout << "Not using some_function_1" << endl;
}

void some_function_2() {
    return some_function_2_impl(0);
}   

Тем не менее, я получаю это сообщение об ошибке:

main.cpp:4:60: error: 'some_function_1' was not declared in this scope
 auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {

В этом весь смысл, подумал я - я не хочу, чтобы эта перегрузка some_function_2_impl быть определенным, потому что some_function_1 не существует.

Я подумал, что SFINAE требует шаблонов для работы, поэтому я попробовал следующее (это может помочь показать, что я не полностью знаю, что я здесь делаю):

template <int foo>
auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {
    cout << "Using some_function_1" << endl;
    some_function_1();
}

template <int foo>
void some_function_2_impl(long) {
    cout << "Not using some_function_1" << endl;
}

Однако теперь я получаю следующую ошибку:

main.cpp:5:60: error: there are no arguments to 'some_function_1' that 
depend on a template parameter, so a declaration of 'some_function_1'
must be available [-fpermissive]
 auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {

Что я делаю неправильно?

1 ответ

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

Затем выполняется поиск ADL после замены типов. В случае неудачи результатом является ошибка замещения.

Поскольку вызов вашей функции не зависит от типов аргументов, этот метод не будет работать.

Мы все еще можем сделать что-то скромное веселье

template<class T, class...Ts>
struct first_two_match : std::false_type{};
template<class T, class...Ts>
struct first_two_match<T,T,Ts...>:std::true_type{}; // for standard compliance: If the only Ts... that match Ts... is nothing, program ill-formed.
struct secret_type_tag {};
template<class...Ts,
  std::enable_if_t<
    (sizeof...(Ts)==0) || first_two_match<secret_tag_type,Ts...>{}
  >* =nullptr
>
secret_type_tag some_function_1(Ts&&...);

template<bool b>
using bool_t=std::integral_constant<bool, b>;
static const auto some_function_defined = bool_t<
  !std::is_same<secret_tag_type, decltype( some_function_1() )>{}
>;

Сейчас some_function_defined является std::true_type если есть перегрузка some_function_1 это предпочтительнее моего some_function_1(Ts&&...), Как some_function_1(Ts&&...) с очень низким приоритетом, любая "реальная" перегрузка (которая также не является перенаправляющим ссылочным гломером и принимает 0 аргументов) будет предпочтительной.

Создание такой перегрузки с низким приоритетом, которая никогда не выбирается, если есть реальная перегрузка, сложно в более сложных ситуациях.

Это все еще только обнаруживает, если some_function_1 определяется в точке, где some_function_defined создано. Вздор.

Другие вопросы по тегам