Как вызвать шаблонную функцию, если она существует, и что-то еще иначе?

Если Вы хотите удалить предел, предупреждающий в целом, что можно взять следующие шаги:

  1. В PyCharm, нажмите File> Settings
  2. In раздел настроек проекта, нажмите Editor> Inspections
  3. In список, который появляется, разверните Python
  4. В соответствии с Python, прокрутите вниз и нажмите "PEP8 coding style violation"
  5. Щелчок +, кнопка рядом с "Игнорирует ошибки" в нижнем правом
  6. , Выводят E501 и нажимают Apply и/или OK

Sources:

34
задан Jesse Beder 6 September 2009 в 17:23
поделиться

7 ответов

Для имени bar выполняется два поиска. Один из них - это неквалифицированный поиск в контексте определения foo . Другой - зависимый от аргумента поиск в каждом контексте создания экземпляра (но результат поиска в каждом контексте создания экземпляра не может изменять поведение между двумя разными контекстами создания экземпляра).

Чтобы добиться желаемого поведения, вы можете определить резервную функцию в пространстве имен fallback , которое возвращает некоторый уникальный тип.

namespace fallback {
  // sizeof > 1
  struct flag { char c[2]; };
  flag bar(...);
}

Функция bar будет вызываться, если ничего больше совпадает, потому что многоточие имеет худшую стоимость преобразования. Теперь включите этих кандидатов в свою функцию с помощью директивы using fallback , чтобы fallback :: bar включен как кандидат в вызов bar .

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

namespace fallback {
  int operator,(flag, flag);

  // map everything else to void
  template<typename T> 
  void operator,(flag, T const&);

  // sizeof 1
  char operator,(int, flag);
}

Если была выбрана наша функция, то вызов оператора запятой вернет ссылку на int . Если нет или если выбранная функция вернула void , то вызов по очереди вернет void . Затем следующий вызов с флагом в качестве второго аргумента вернет тип с размером 1, если был выбран наш запасной вариант, и размер больше 1 (будет использоваться встроенный оператор запятой, потому что в миксе есть void ), если было выбрано что-то еще.

Мы сравниваем sizeof и delegate со структурой.

template<bool>
struct foo_impl;

/* bar available */
template<>
struct foo_impl<true> {
  template<typename T>
  static void foo(T const &t) {
    bar(t);
  }
};

/* bar not available */
template<>
struct foo_impl<false> {
  template<typename T>
  static void foo(T const&) {
    std::cout << "not available, calling baz...";
  }
};

template <typename T>
void foo(const T& t) {
   using namespace fallback;

   foo_impl<sizeof (fallback::flag(), bar(t), fallback::flag()) != 1>
     ::foo(t);
}

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

struct C { };
int main() {
  // => "not available, calling baz..."
  foo(C());
}

И если кандидат найден с использованием зависимого от аргумента поиска

struct C { };
void bar(C) {
  std::cout << "called!";
}
int main() {
  // => "called!"
  foo(C());
}

Чтобы проверить неквалифицированный поиск в контексте определения, давайте определим следующую функцию выше foo_impl и foo (поместите шаблон foo_impl выше foo , чтобы у них был один и тот же контекст определения)

void bar(double d) {
  std::cout << "bar(double) called!";
}

// ... foo template ...

int main() {
  // => "bar(double) called!"
  foo(12);
}
33
ответ дан 27 November 2019 в 17:00
поделиться

litb дал вам очень хороший ответ . Однако мне интересно, не могли бы мы, учитывая больший контекст, придумать что-то менее общее, но и менее, ммм, , ?

Например, какие типы могут быть T ? Что-нибудь? Несколько видов? Очень ограниченный набор, который вы контролируете? Какие классы вы разрабатываете вместе с функцией foo ? Учитывая последнее, вы можете просто поместить что-то вроде

typedef boolean<true> has_bar_func;

в типы, а затем переключиться на разные перегрузки foo на основе этого:

template <typename T>
void foo_impl(const T& t, boolean<true> /*has_bar_func*/);
template <typename T>
void foo_impl(const T& t, boolean<false> /*has_bar_func*/);

template <typename T>
void foo(const T& t) {
  foo_impl( t, typename T::has_bar_func() );
}

Также можно bar / ] baz имеет практически любую подпись, есть ли несколько ограниченный набор или только одна действительная подпись? Если последнее, то запасная идея litb (отличная), в сочетании с метафункцией, использующей sizeof , может быть немного проще. Но это я не исследовал, так что это просто мысль.

6
ответ дан 27 November 2019 в 17:00
поделиться

Я думаю, что решение litb работает, но слишком сложно. Причина в том, что он вводит функцию fallback :: bar (...) , которая действует как «функция последней инстанции», а затем делает все возможное, чтобы НЕ вызывать ее. Почему? Кажется, у нас есть идеальное поведение для него:

namespace fallback {
    template<typename T>
    inline void bar(T const& t, ...)
    {
        baz(t);
    }
}
template<typename T>
void foo(T const& t)
{
    using namespace fallback;
    bar(t);
}

Но, как я указал в комментарии к исходному сообщению litb, есть много причин, по которым bar (t) может не компилироваться, и я не уверен, что это решение обрабатывает те же случаи. Это определенно не сработает на приватном баре :: bar (T t)

3
ответ дан 27 November 2019 в 17:00
поделиться

Если вы хотите ограничиться Visual C ++, вы можете использовать __ if_exists и __ if_not_exists .

Удобно в крайнем случае, но зависит от платформы.

2
ответ дан 27 November 2019 в 17:00
поделиться

РЕДАКТИРОВАТЬ: Я заговорил слишком рано! ответ litb показывает, как это можно сделать на самом деле (возможной ценой вашего здравомыслия ... :-P)

К сожалению, я думаю, что общий случай проверки "будет ли эта компиляция" недоступен из вывода аргументов шаблона функции + SFINAE , что является обычным трюком для этого материала. Я думаю, лучшее, что вы можете сделать, - это создать шаблон функции «резервного копирования»:

template <typename T>
void bar(T t) {   // "Backup" bar() template
    baz(t);
}

А затем заменить foo () на просто:

template <typename T>
void foo(const T& t) {
    bar(t);
}

Это будет работать в большинстве случаев. Поскольку тип параметра шаблона bar () - T , он будет считаться «менее специализированным» при сравнении с любой другой функцией или шаблоном функции с именем bar () и, следовательно, уступит приоритет этой ранее существовавшей функции или шаблону функции во время разрешения перегрузки. За исключением того, что:

  • Если ранее существовавший bar () сам является шаблоном функции, принимающим параметр шаблона типа T , возникнет двусмысленность, потому что ни один шаблон не является более специализированным, чем другой, и компилятор будет жаловаться.
  • Неявные преобразования также не будут работать и приведут к трудно диагностируемым проблемам: предположим, что существует уже существующая полоса (длинная) , но вызывается foo (123) . В этом случае компилятор незаметно выберет создание экземпляра шаблона «backup» bar () с T = int вместо выполнения int-> долгое продвижение, даже если последний компилировался и работал бы нормально!

Короче говоря: нет простого, полного решения, и я почти уверен, что нет даже чертовски сложного, полного решения. : (

2
ответ дан 27 November 2019 в 17:00
поделиться
//default

////////////////////////////////////////// 
    template <class T>
    void foo(const T& t){
        baz(t);
    }

//specializations
//////////////////////////////////////////  

    template <>
    void foo(const specialization_1& t){
        bar(t);
    }
    ....
    template <>
    void foo(const specialization_n& t){
        bar(t);
    }
2
ответ дан 27 November 2019 в 17:00
поделиться

Вы не можете использовать здесь полную специализацию (или перегрузку) на foo. Скажем, у вас есть панель вызова шаблона функции, но для определенных типов она полностью специализируется на вызове baz?

0
ответ дан 27 November 2019 в 17:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: