C++11和C++14中的“bsearch”规范是否有缺陷?

45

在回答这个问题之后,无论是C++11还是C++14:

[C++11, C++14: 25.5/2]: 内容与标准C库头文件<stdlib.h>相同,但以下内容除外:

[C++11, C++14: 25.5/3]: 函数签名为:

bsearch(const void *, const void *, size_t, size_t,
        int (*)(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 *));

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

这两个声明具有与原始声明相同的行为。

然而,

  

[C++11,C++14:7.5 / 5]:如果两个声明声明具有相同名称和参数类型列表(8.3.5)的函数为同一命名空间的成员,或者声明具有相同名称的对象为同一命名空间的成员,并且声明为不同的语言链接提供了名称,则程序是有缺陷的;如果声明出现在不同的翻译单位中,则不需要进行诊断。 [..]

这是一个缺陷吗?


答案取决于这两个函数是否具有相同的参数。如果链接是类型的一部分,则在这两个示例中,compar 具有不同的类型...尽管如果是这样的话,我想要一些简单的方法来为类型声明它,但我不知道有没有这样的方法。 - Deduplicator
在标准C++中,您可以使用模板别名。template <typename R, typename...T> using CxxFunc = R(T...); extern "C" { template <typename R, typename...T> using CFunc = R(T...); }。将compar声明为CFunc<int,const void*,const void*>CxxFunc<...>。大多数实现都会拒绝它,因为它们不允许在extern "C"块中使用模板,但这是完全有效的。限制是模板不能具有extern "C"链接,而不是模板不能出现在extern "C"块中。模板别名没有语言链接,所以没问题。 - user743382
1
在C++98 25.4/3中也是同样的方式(对于qsort,还有25.4/4)。 - Cubbi
1个回答

49

但参数类型列表不同。在一个中,compar是指向具有 "C" 语言链接的函数的指针,在另一个中,它是指向具有 "C++" 语言链接的函数的指针。

C++11,7.5规定:

  

1...即使它们在其他方面相同,具有不同语言链接的两种函数类型也是不同的类型。

  

4在一个链接说明符中,指定的语言链接适用于所有函数声明符的函数类型,具有外部链接的函数名称以及在链接说明符内声明的具有外部链接的变量名称。[示例:

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
意思是7.5/1和7.5/5之间的看似不一致,在意识到1谈论函数类型,而5则涉及函数名称时得以解决。

5
似乎无论是clang++还是g++都认为它们是相同的。http://coliru.stacked-crooked.com/a/ceb69c605e32832d - Deduplicator
@Deduplicator 我猜他们各自的标准库中没有这两个函数(可能是根据 as-if 规则)。 - Angew is no longer proud of SO
5
如果它们无法区分链接的类型,那么它们别无选择。因此,这是一个漏洞并且利用了它。 - Deduplicator
一般来说,您可以获取标准库函数的地址并将其传递给模板函数,该函数可以接受指向 C 语言链接函数或 C++ 语言链接函数的指针。但是对于重载函数,不清楚应该选择哪个重载函数。 - user743382
1
@Yakk 忘记函数类型语言链接是明显的符合性问题,毫无疑问。当您获取任何标准库函数的指针时,不能假设任何特定的语言链接。您可能会得到一个具有C链接的函数或具有C++链接的函数,您唯一可以使用它的方式是在任何一个都可以工作的上下文中(decltypeauto或推断的模板参数)。 - user743382
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接