45

Following on from my answer to this question, in both C++11 and C++14:

[C++11, C++14: 25.5/2]: The contents are the same as the Standard C library header <stdlib.h> with the following exceptions:

[C++11, C++14: 25.5/3]: The function signature:

bsearch(const void *, const void *, size_t, size_t,
        int (*)(const void *, const void *));

is replaced by the two declarations:

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

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

both of which have the same behavior as the original declaration.

However,

[C++11, C++14: 7.5/5]: If two declarations declare functions with the same name and parameter-type-list (8.3.5) to be members of the same namespace or declare objects with the same name to be members of the same namespace and the declarations give the names different language linkages, the program is ill-formed; no diagnostic is required if the declarations appear in different translation units. [..]

Is this a defect?

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • The answer hinges on those two functions having the same arguments or not. If linkage is part of the type, `compar` has a different type in both examples... though if it is, I want some easy way to declare it for types, and I'm not aware of any. – Deduplicator Oct 02 '14 at 12:57
  • @Deduplicator In standard C++, you would be able to make use of template aliases. `template using CxxFunc = R(T...); extern "C" { template using CFunc = R(T...); }`. Declare `compar` as `CFunc` and `CxxFunc<...>`. Most implementations reject it because they disallow templates in `extern "C"` blocks, but it's perfectly valid. The restriction is that a template cannot have `extern "C"` linkage, not that a template cannot appear in an `extern "C"` block. A template alias has no language linkage, so it's fine. –  Oct 02 '14 at 13:29
  • 1
    It's the same way in C++98 25.4/3 (and 25.4/4 for `qsort`) – Cubbi Oct 03 '14 at 01:10

1 Answers1

49

But the parameter types list are not the same. In one, compar is a pointer to a function with "C" language linkage, in the other one, it's a pointer to a function with "C++" language linkage.

C++11, 7.5 specifies:

1 ... Two function types with different language linkages are distinct types even if they are otherwise identical.

4 In a linkage-specification, the specified language linkage applies to the function types of all function declarators, function names with external linkage, and variable names with external linkage declared within the linkage-specification. [ Example:

extern "C" void f1(void(*pf)(int));
// the name f1 and its function type have C language
// linkage; pf is a pointer to a C function

The seeming inconsistency between 7.5/1 and 7.5/5 is solved when realising that 1 talks about function types, while 5 addresses function names.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Is there any easy way to declare that the first fp has C++ and the second C linkage, for a function expecting two function-pointers? – Deduplicator Oct 02 '14 at 13:01
  • @Deduplicator Use a `typedef` for the parameter which differs from the contained function's language linkage. – Angew is no longer proud of SO Oct 02 '14 at 13:03
  • 5
    Seems neither clang++ nor g++ regard them as different though. http://coliru.stacked-crooked.com/a/ceb69c605e32832d – Deduplicator Oct 02 '14 at 13:04
  • @Deduplicator I'd guess their respective standard libraries don't contain the two functions, then (probably under the as-if rule). – Angew is no longer proud of SO Oct 02 '14 at 13:06
  • 5
    Well, they have no other choice if they fail to differentiate types on linkage. So, a bug and making the most of it. – Deduplicator Oct 02 '14 at 13:08
  • @angew except if I create two different function types, one `"C++"` the other `"C"`, and cast `bsearch` to pointers to each, ... hmm, there may be no standards compliant way to compare those two pointers to know if they are the same or different. (function pointers being strange beasts) If there where, the as-if would fail, as the above explicitly states there are two different functions. – Yakk - Adam Nevraumont Oct 02 '14 at 13:20
  • @Yakk There may not even be a standards compliant way to take a pointer to one of those overloads. Even with the explicit `extern "C"`, the language linkage of standard library functions is unspecified, so the explicit `extern "C"` is only required to apply to the parameter type, and the first `bsearch` overload is allowed to be a C++-linkage function with a pointer-to-C-linkage-function as one of its parameters. Taking its address to assign it to a pointer-to-C-linkage-function would be ill-formed on such an implementation. –  Oct 02 '14 at 13:23
  • @Yakk Generally, you can take the address of standard library functions and pass it to template functions, that can take either a pointer-to-C-linkage-function or a pointer-to-C++-linkage-function, but for overloaded functions, it would be unclear which overload should be picked. –  Oct 02 '14 at 13:24
  • @hvd To be clearer, two function types, one of which takes a pointer to a `"C++"` linkage function, and another that takes a pointer to a `"C"` linkage function, and cast `bsearch` to a variable of type pointer-to-each. As the standard states there are two functions, if we could compare these two function pointers for identity, the as-if rule might be violated by gcc/clang here. I suppose if the language linkage is unspecified, it might not be legal to take a pointer to **any** `std` function however (other than as a `decltype` or `auto`)? – Yakk - Adam Nevraumont Oct 02 '14 at 13:42
  • 1
    @Yakk Failing to remember function type language linkage is a definite conformance issue, no question about that. And yes, when you take a pointer to any standard library function, you must not assume any particular language linkage. You might get a function with C linkage, or a function with C++ linkage, and the only way you can use that is in contexts where either would work (`decltype`, `auto`, or deduced template arguments) –  Oct 02 '14 at 13:56