1

我正在尝试将一些代码从 to 迁移boost::tuplestd::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 和 boost 1.55.0。你认为这是boost的错误吗?还是我缺少一些规范?

4

1 回答 1

4

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

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

ADL 添加与函数调用的参数关联boost::的命名空间,在这种情况下是(基本类型,如int没有关联的命名空间)。此时编译器看到tie:std::tie和的两个声明boost::tie,导致歧义。

正如您已经知道的那样,解决方案是对调用进行限定std::tie(我建议您即使没有这个问题也可以使用)。关于评论:

如果 ADL 决定为...“我的方便”而使用 boost::tie,然后编译失败,这不应该是编译器选择错误函数的线索吗?!

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

请注意,通常编译过程总是向前推进的,编译器不会回溯以双重猜测自己的决定*。有一套规则,这些规则适用于每一步。如果有歧义,编译停止,如果没有,则只有一个最佳候选者,这一点得到解决,进入下一个。尝试返回撤消决策会使编译过程变得非常缓慢(可以采用的路径数量将呈指数级增长)。

*与往常一样,有一些例外,但这些只是例外,特别是在重载决议期间,如果模板被选为最佳候选但类型参数的替换失败,则将其丢弃并选择下一个最佳候选。

于 2013-11-19T13:46:48.607 回答