Вопрос

In C++, there are two versions of qsort() provided by the standard library:

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() is about the same.

My question is, how does overload resolution work when calling qsort()? Does it automatically link to the appropriate function based on the linkage type ("C" or "C++") of the function pointer passed as the last argument? Or the caller needs to specify explicitly with some sort of extra syntax?

(Let's just put away the temptation to call std::sort for a second...)

Это было полезно?

Решение

The int (*compar)(const void*, const void*) parameter has different types for the two different overloads. For the first overload, it's an extern "C" function pointer parameter. For the second overload, it's an extern "C++" function pointer parameter. Any function pointer you pass to qsort will already have some sort of linkage, and that is what gets used to determine which overload to call.

To quote the standard:

7.5 Linkage specifications [dcl.link]

All function types, function names with external linkage, and variable names with external linkage have a language linkage. [...] The default language linkage of all function types, function names, and variable names is C++ language linkage. Two function types with different language linkages are distinct types even if they are otherwise identical.

In fact, I don't think the standard actually means to require that the two qsort overloads really do have different linkage. Unlike in C, user-provided declarations of standard library functions are not allowed; the relevant difference between them is the type of compar. They could have been declared as

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);

where it should be more obvious that __compar_fnp_c and __compar_fnp_cxx are different types. That said, the as-if rule doesn't allow this implementation, since it would break code that takes a pointer or reference to qsort.

Note that GCC, as well as some other compilers, don't implement this correctly, and don't treat linkage as part of the function pointer's type. On such implementations, only one version of qsort will have been made available, to prevent a conflict during overload resolution.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top