我正在尝试将一些代码从boost::tuple
迁移到std::tuple
,但我收到一些奇怪的错误:在我调用using namespace std
(并且从不boost
)之后,我期望不合格tie
解析为std::tie
。但是,例如,当元组包含一个boost容器指针时,这似乎失败了。
#include <tuple>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#ifdef USE_STD
#define TIE std::tie
#else
#define TIE tie
#endif
typedef boost::multi_index_container<
int,
boost::multi_index::indexed_by<
boost::multi_index::ordered_non_unique<
boost::multi_index::identity<int>
>
>
> Set;
std::tuple< int, int* > make_i_ptr();
std::tuple< int, Set* > make_set();
int main()
{
using namespace std;
int i;
int* i_ptr;
Set* set_ptr;
tie(i, i_ptr) = make_i_ptr();
TIE(i, set_ptr) = make_set();
return 0;
}
如果我使用g++ -std=c++0x -c test.cpp -DUSE_STD
编译,一切都很好。但是,如果没有-D USE_STD
,我会收到编译错误,表明g++
尝试使用boost::tuples::tie
。我正在使用g ++ 4.8.1并提升1.55.0。你认为这是一个提升的错误吗?或者是否有一些我缺少的规格?
答案 0 :(得分:4)
查找很复杂。其他人提到的问题是Argument Dependent Lookup或ADL。添加了ADL的规则,以允许在与它们引用的类型相同的命名空间中定义运算符,并使查找能够在存在时查找这些运算符。后来扩展到标准化过程中的所有其他功能。
这里的问题是tie(...)
是函数调用。编译器将尝试从使用点(在main
内)进行定期查找,它将移出到封闭的命名空间。 using命令会在查找根命名空间(::std
和::std
的共同祖先)时将::main
添加到查找搜索中。此时,由于标识符解析为函数,ADL将启动。
ADL将名称空间关联添加到函数调用的参数中,在本例中为boost::
(基本类型如int
没有关联的名称空间)。此时,编译器会看到tie
:std::tie
和boost::tie
的两个声明,从而导致歧义。
正如您已经知道的解决方案是将调用限定为std::tie
(即使没有此问题,我建议您使用)。关于评论:
如果ADL让它解决了boost :: tie for ...“我的方便”然后编译失败了,那不应该是编译器选择错误函数的线索吗?!
我不知道你得到的确切错误是什么(我不使用boost,我不知道它包含的std::tie
可能有多少重载)。如果问题确实存在歧义,问题在于编译器无法解析标识符,并且无法继续该过程。此时它停止并要求程序员解决它。如果错误是它唯一选择boost::tie
并且稍后在分配中失败,则意味着theres是boost::tie
的重载,其匹配比std::tie
更好并且已被选中。稍后从std::tuple
的赋值可能失败,但编译器无法知道问题是在查找期间,还是它是否是赋值本身(您是否打算分配该变量?可能是另一个?)所以它再次失败并告诉你问题是什么。
请注意,一般来说,编译过程始终是 forward ,编译器不会回溯以加倍猜测自己的决定 * 。有一组规则,每个步骤都应用这些规则。如果存在歧义,编译会停止,如果没有,则会有一个最佳候选者,并且此点已解决,然后移至下一个。尝试回到撤销决策会使编译过程变得非常缓慢(可以采用的路径数量将呈指数级)。
* 一如既往有一些例外,但这些只是异常,特别是在重载解析期间,如果选择模板作为最佳候选者但是类型参数的替换失败,它将被丢弃并且是次佳的候选人被选中。