Разрешение перегрузки на внешнем «C» и «C ++»; версия qsort () / bsearch ()

В C ++ есть две версии qsort() предоставляется стандартной библиотекой:

extern "C" void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
extern "C++" void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));

bsearch() примерно так же.

Мой вопрос, как работает разрешение перегрузки при вызове qsort()? Будет ли он автоматически ссылаться на соответствующую функцию на основе типа связи («C» или «C ++») указателя функции, переданного в качестве последнего аргумента? Или вызывающий должен указать явно с каким-то дополнительным синтаксисом?

(Давайте просто уберем искушение позвонить std::sort на секунду…)

6

Решение

int (*compar)(const void*, const void*) Параметр имеет разные типы для двух разных перегрузок. Для первой перегрузки это extern "C" параметр указателя функции. Для второй перегрузки это extern "C++" параметр указателя функции. Любой указатель на функцию, которую вы передаете qsort уже будет иметь какую-то связь, и это то, что используется, чтобы определить, какую перегрузку вызывать.

Чтобы процитировать стандарт:

7.5 Спецификации сцепления [dcl.link]

Все типы функций, имена функций с внешней связью и имена переменных с внешней связью имеют языковая связь. […] Языковая связь по умолчанию для всех типов функций, имен функций и имен переменных — это языковая связь C ++. Два типа функций с разными языковыми связями являются разными типами, даже если они идентичны.

На самом деле, я не думаю, что стандарт на самом деле означает, что два qsort перегрузки действительно имеют различную связь. В отличие от C, пользовательские объявления стандартных функций библиотеки не допускаются; соответствующая разница между ними является тип compar, Они могли быть объявлены

extern "C" typedef int (*__compar_fnp_c)(const void *, const void *);
extern "C++" typedef int (*__compar_fnp_cxx)(const void *, const void *);
void qsort(void* base, size_t nmemb, size_t size, __compar_fnp_c compar);
void qsort(void* base, size_t nmemb, size_t size, __compar_fnp_cxx compar);

где должно быть более очевидно, что __compar_fnp_c а также __compar_fnp_cxx разные типы. Тем не менее, правило «как если» не допускает такую ​​реализацию, поскольку оно нарушит код, который принимает указатель или ссылку на qsort,

Обратите внимание, что GCC, как и некоторые другие компиляторы, не реализуют это правильно и не рассматривают связывание как часть типа указателя функции. На таких реализациях только одна версия qsort будет сделано доступным, чтобы предотвратить конфликт при разрешении перегрузки.

3

Другие решения

Других решений пока нет …