2

我在公司内部将一些代码从一个项目移植到另一个项目,但遇到了一个无法编译的通用“sets_intersect”函数:

template<typename _InputIter1, typename _InputIter2, typename _Compare>
bool sets_intersect(_InputIter1 __first1, _InputIter1 __last1,
                    _InputIter2 __first2, _InputIter2 __last2,
                    _Compare __comp)
{
    // Standard library concept requirements
    // These statements confuse automatic indentation tools.
    // concept requirements
    __glibcpp_function_requires(_InputIteratorConcept<_InputIter1>)
    __glibcpp_function_requires(_InputIteratorConcept<_InputIter2>)
    __glibcpp_function_requires(_SameTypeConcept<
          typename iterator_traits<_InputIter1>::value_type,
          typename iterator_traits<_InputIter2>::value_type>)
    __glibcpp_function_requires(_OutputIteratorConcept<_OutputIter,
          typename iterator_traits<_InputIter1>::value_type>)
    __glibcpp_function_requires(_BinaryPredicateConcept<_Compare,
          typename iterator_traits<_InputIter1>::value_type,
          typename iterator_traits<_InputIter2>::value_type>)

    while (__first1 != __last1 && __first2 != __last2)
    if (__comp(*__first1, *__first2))
            ++__first1;
    else if (__comp(*__first2, *__first1))
            ++__first2;
    else {
            return true;
    }
    return false;
}

我对“概念”这个概念不熟悉(对不起,双关语),所以我在 c++ 标准库中进行了一些探索和一些谷歌搜索,我可以看到这些__glibcpp_function_requires宏已更改为__glibcxx_function_requires. 这样就修复了我的编译器错误;但是,由于这对我来说是新的,我很好奇这段代码为我做了什么,而且我在查找任何文档或解密库中的代码时遇到了麻烦。

我假设这些宏的意义在于,当编译器扩展模板化函数时,它们将在编译时运行一些类型检查,以查看所使用的容器是否与该算法兼容。换句话说,我假设第一个调用是检查是否_InputIter1符合_InputIteratorConcept. 我只是困惑还是我走在正确的轨道上?另外,为什么这些宏的名称在 c++ 标准库中被更改了?

4

4 回答 4

3

“概念”是下一个版本的提议功能C++,但它们(相对)最近被投票排除在标准之外,因此现在不会重新出现以供引用。

它们旨在允许早期检查模板参数的要求,并且除其他外,当使用不满足所需约束的类型来实例化模板时,将启用更简洁的错误消息。

第二次编辑:(见 dribeas 和 Jerry Coffin 的评论)这些 g++ 宏是一种内部概念检查机制,与提议的同名新语言特性没有直接关系。由于它们是 g++ 内部的,因此您可以(也许应该)安全地删除它们,而不会丢失函数模板中的任何功能。

于 2009-10-27T22:17:34.590 回答
1

你是对的,第一个调用是检查_InputIter1实现“输入迭代器”概念

这些宏是内部 GLIBC 实现细节(以下划线或双下划线开头),因此 GLIBC 实现者可以随意更改它们。它们不应该被用户的代码使用。

由于“概念”不再是 C++0x 草案的一部分,为了进行可移植的概念检查,您应该使用一些第三方库,例如Boost 概念检查库

于 2009-10-27T22:29:08.530 回答
1

周围有两个概念概念(双关语)。正在定义的标准提出了将概念作为标准语言功能的提议,这将有助于编译,并且......有很多关于 C++0x 概念的文献,讨论......

另一个概念概念是你刚刚打的那个。与 g++ 实现一起部署的 STL 确实具有特定的实现者检查,这些检查也有助于错误检测。这些与之前的概念不同,因为它们不是语言特性,也不打算供程序员使用,而是在库内部使用。由于名称是保留的(它们以双下划线开头),只要库的行为与标准定义的不同,编译器/库实现者就可以自由添加任何内容。

回到您正在做的事情:您尝试移植到较新编译器的代码是std::set_intersect标准 [lib.set.intersection] 中定义的修改版本,仅返回它们是否相交,而无需解析整个两个范围。我会使用标准版本并检查输出迭代器是否未被修改,或者如果它是性能问题,则在没有概念检查的情况下实现它,这取决于非标准隐藏编译器定义的符号在升级编译器时要求维护麻烦. 但你已经知道了。

于 2009-10-27T22:47:52.110 回答
0

正如查尔斯已经指出的那样,作为 C++ 0x 的一部分的对概念的直接支持最近才从该语言中删除,而且几乎可以肯定,在下一轮标准化之前,它们甚至不会被重新考虑。希望到那时,他们真正应该做什么/做什么会有更大的共识。

不过,相当多的库试图提供类似的功能。Boost Concept Check Library可能是最明显的,我相信大多数其他的都是基于它,至少在概念上(如果你会原谅双关语)。至于为什么 g++ 家伙决定从 '*cxx' 更改为 '*cpp',我什至无法猜测——除了他们似乎认为尽可能多地打破向后兼容性是一件好事(尽管这些实际上仅用于内部使用,因此更改名称不应该破坏太多,而是它们自己的代码)。

这也与 Andrei Alexandrescu 在Modern C++ Design §2.1 中提出的基本思想非常相似。如果您想了解如何编写自己的概念检查,您可能需要阅读它(以及 §2.7,他在其中应用类似的技术来测试可转换性和继承性)。虽然检查的概念各不相同,但它们很好地解释了大多数基本技术,所以:

  1. 你很有机会阅读和理解概念检查模板
  2. 如果你决定自己写一些,你有一个起点

编辑:可能值得注意的是,大多数当前 C++ 编译器的标准库至少包含某种概念检查模板。显然gnu可以。科莫也是如此。事实上,我能想到的唯一一个似乎不再包含任何此类东西的是 MS VC++(它使用 Dinkumware 库)。他们主要集中在一些(相当昂贵的)运行时调试上。这也有点用处,但方向完全不同,两者根本不相互排斥。

于 2009-10-27T22:42:54.897 回答