我在公司内部将一些代码从一个项目移植到另一个项目,我遇到了一个无法编译的通用“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 ++标准库中发生了变化?
答案 0 :(得分:3)
“概念”是C++
的下一版本的建议功能,但它们(相对)最近被投票退出标准,因此现在不会重新报价。
它们旨在允许及早检查模板参数的要求,除其他外,当使用不符合所需约束的类型来实例化模板时,它将启用更简洁的错误消息。
2nd Edit:(参见dribeas和Jerry Coffin的评论)这些g ++宏是一种内部概念检查机制,与提议的同名新语言功能没有直接关系。因为它们是g ++的内部元素,所以你可以(也许应该)安全地删除它们而不会丢失函数模板中的任何功能。
答案 1 :(得分:1)
你是对的,第一个调用是检查_InputIter1
实现“输入迭代器”concept。
这些宏是内部GLIBC实现细节(以下划线或双下划线开头),因此允许GLIBC实施者随意更改它们。它们不应该被用户代码使用。
由于“概念”不再是C ++ 0x草案的一部分,为了进行便携式概念检查,您应该使用某些第三方库,例如Boost Concept Check Library。
答案 2 :(得分:1)
有两个概念概念(双关语)。正在定义的标准有一个提议 concepts 作为标准语言特性,有助于编译和...有很多关于C ++ 0x概念,讨论的文献。
其他概念概念就是您刚刚遇到的概念。使用g ++实现部署的STL确实具有特定的实现者检查,这也有助于错误检测。这些与以前的概念不同,因为它们不是语言特性,并且不打算由程序员使用,而是在库内部使用。由于名称是保留的(它们以双下划线开头),只要库的行为与标准定义的内容没有区别,编译器/库实现者就可以自由添加任何内容。
回到您正在做的事情:您尝试移植到较新编译器的代码是标准[lib.set.intersection]中定义的std::set_intersect
的修改版本,仅返回它们是否为交叉而不必解析整个两个范围。我要么使用标准版本并检查输出迭代器是否未被修改,或者是否是性能问题,请在没有概念检查的情况下实现它,具体取决于非标准的隐藏编译器定义符号在升级编译器时要求维护麻烦。但是你已经知道了。
答案 3 :(得分:0)
正如Charles已经指出的那样,作为C ++ 0x的一部分的概念的直接支持最近才被从语言中删除,并且在下一轮标准化之前几乎肯定不会重新考虑它们。希望届时会对他们应该做什么/做什么有更大的一致。
相当数量的图书馆试图提供类似的功能。 Boost Concept Check Library可能是最明显的,我相信其他大多数都基于它,至少在概念上(如果你原谅双关语)。至于为什么g ++家伙决定从'* cxx'改为'* cpp',我甚至无法开始猜测 - 除此之外,他们似乎认为尽可能经常破坏向后兼容性是一件好事(尽管这些只是供内部使用,所以更改名称不应该打破很多但是他们自己的代码。)
这与Andrei Alexandrescu在 Modern C ++ Design 的§2.1中提出的基本思想非常相似。如果你想知道如何编写自己的概念检查,你可能想要阅读它(以及§2.7,他将类似的技术应用于测试可转换性和继承)。虽然所检查的概念各不相同,但它们很好地解释了大多数基本技术,所以:
编辑:值得注意的是,大多数当前C ++编译器的标准库至少包含某种概念检查模板。显然gnu确实如此。 Comeau也是。实际上,我能想到的唯一一个似乎不再包含任何此类东西的是MS VC ++(它使用Dinkumware库)。他们主要集中在一些(相当昂贵的)运行时调试上。这也有些用处,但是方向完全不同,两者根本不相互排斥。