C++ 11,以后再定义free函数begin,end,emptystd下等.对于大多数容器,这些函数调用相应的成员函数.但是对于某些容器(例如valarray),这些自由函数被重载(initializer_list没有成员begin()).因此,要迭代任何容器,应该使用自由函数,并且应该使用除stdADL 之外的命名空间的容器函数:
template<typename C>
void foo(C c)
{
using std::begin;
using std::end;
using std::empty;
if (empty(c)) throw empty_container();
for (auto i = begin(c); i != end(c); ++i) { /* do something */ }
}
Run Code Online (Sandbox Code Playgroud)
问题1:我是否正确?正在begin和end预计通过ADL被发现?
但是ADL规则指定如果参数的类型是类模板,则特殊化ADL包括所有模板参数的名称空间.然后Boost.Range库进场时,它定义了boost::begin,boost::end等等,这些功能是这样定义的:
template< class T >
inline BOOST_DEDUCED_TYPENAME range_iterator<T>::type begin( T& r )
{
return range_begin( r );
}
Run Code Online (Sandbox Code Playgroud)
如果我使用std::vector<boost::any>和Boost.Range我遇到麻烦.std :: begin和boost :: begin重载是不明确的.它,我不能写模板代码,将begin通过ADL 找到一个免费的.如果我明确使用,std::begin我希望任何非std::容器都有一个成员begin.
问题2:在这种情况下我该怎么办?
依靠成员函数的存在?最简单的方法.
Ban Boost.Range?好吧,采用容器而不是一对迭代器的算法很方便.Boost.Range适配器(懒惰地将算法应用于容器的容器)也很方便.但是如果我不在我的代码中使用Boost.Range,它仍然可以在boost库中使用(除了Range).这使得模板代码非常脆弱.
禁止提升?
几年前,我遇到了类似的问题,我的代码突然开始在std::begin和之间出现歧义boost::begin。我发现这是由于使用Boost.Operator来帮助定义一个类,即使它甚至不是一个公共基类,或者对于所涉及类型的用户来说不是显而易见的。某处的随机更改导致#include <boost/range/begin.hpp>出现在某处的嵌套包含文件中,从而使得boost::begin对编译器可见。
我向邮件列表抱怨将类直接放在 Boost 命名空间中,而不是放在嵌套类中并通过using声明公开它们;直接在 Boost 命名空间中定义的所有内容都可能通过意外的 ADL 相互干扰。
我今天刚刚尝试重现这一点,现在它似乎对这种歧义很有弹性!查看定义,boost::begin它本身位于内部名称空间中,因此如果您没有在自己的范围内提供自己的名称空间,则永远无法通过不合格的查找找到它。using boost::begin;
我不知道\xe2\x80\x99不知道这个修复发生了多久。(如果您仍然可以重现它,请发布包含版本和平台详细信息的完整程序。)
\n对于Boost,不用再担心\xe2\x80\x99(必要时升级Boost)。
\nbegin对于新代码,切勿定义与其任何已定义类型在同一命名空间中命名的自由函数。