c ++ 11领带名称与boost冲突

时间:2013-11-18 23:44:46

标签: c++ boost c++11 boost-tuples stdtuple

我正在尝试将一些代码从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。你认为这是一个提升的错误吗?或者是否有一些我缺少的规格?

1 个答案:

答案 0 :(得分:4)

查找很复杂。其他人提到的问题是Argument Dependent Lookup或ADL。添加了ADL的规则,以允许在与它们引用的类型相同的命名空间中定义运算符,并使查找能够在存在时查找这些运算符。后来扩展到标准化过程中的所有其他功能。

这里的问题是tie(...)是函数调用。编译器将尝试从使用点(在main内)进行定期查找,它将移出到封闭的命名空间。 using命令会在查找根命名空间(::std::std的共同祖先)时将::main添加到查找搜索中。此时,由于标识符解析为函数,ADL将启动。

ADL将名称空间关联添加到函数调用的参数中,在本例中为boost::(基本类型如int没有关联的名称空间)。此时,编译器会看到tiestd::tieboost::tie的两个声明,从而导致歧义。

正如您已经知道的解决方案是将调用限定为std::tie(即使没有此问题,我建议您使用)。关于评论:

  

如果ADL让它解决了boost :: tie for ...“我的方便”然后编译失败了,那不应该是编译器选择错误函数的线索吗?!

我不知道你得到的确切错误是什么(我不使用boost,我不知道它包含的std::tie可能有多少重载)。如果问题确实存在歧义,问题在于编译器无法解析标识符,并且无法继续该过程。此时它停止并要求程序员解决它。如果错误是它唯一选择boost::tie并且稍后在分配中失败,则意味着theres是boost::tie的重载,其匹配比std::tie更好并且已被选中。稍后从std::tuple的赋值可能失败,但编译器无法知道问题是在查找期间,还是它是否是赋值本身(您是否打算分配该变量?可能是另一个?)所以它再次失败并告诉你问题是什么。

请注意,一般来说,编译过程始终是 forward ,编译器不会回溯以加倍猜测自己的决定 * 。有一组规则,每个步骤都应用这些规则。如果存在歧义,编译会停止,如果没有,则会有一个最佳候选者,并且此点已解决,然后移至下一个。尝试回到撤销决策会使编译过程变得非常缓慢(可以采用的路径数量将呈指数级)。

* 一如既往有一些例外,但这些只是异常,特别是在重载解析期间,如果选择模板作为最佳候选者但是类型参数的替换失败,它将被丢弃并且是次佳的候选人被选中。