为什么 ::boost::tie 不能与 BOOST_FOREACH 一起使用?
Why doesn't ::boost::tie work with BOOST_FOREACH?
我想使用 BOOST_FOREACH
迭代 boost::ptr_map
,结果遇到了 this neat-looking solution。与给出的其他解决方案相比,我更愿意使用它来提高可读性。我写了下面的代码:
boost::ptr_map<int, std::string> int2strMap;
int x = 1;
int2strMap.insert(x, new std::string("one"));
int one;
std::string* two;
BOOST_FOREACH(::boost::tie(one, two), int2strMap)
{
std::cout << one << two << std::endl;
}
但是,编译失败,并出现以下错误(完整的错误消息还有几行,如果我应该粘贴它们请告诉我。):
error: no match for 'operator=' (operand types are 'boost::tuples::detail::tie_mapper<int, std::basic_string<char>*, void, void, void, void, void, void, void, void>::type {aka boost::tuples::tuple<int&, std::basic_string<char>*&, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>}' and 'boost::iterators::iterator_reference<boost::ptr_map_iterator<std::_Rb_tree_iterator<std::pair<const int, void*> >, int, std::basic_string<char>* const> >::type {aka boost::ptr_container_detail::ref_pair<int, std::basic_string<char>* const>}')
BOOST_FOREACH(::boost::tie(one, two), int2strMap)
建议的解决方案似乎适用于少数人,我无法弄清楚为什么它对我不起作用。我在这里做错了什么?
(注意:我正在做一个史前项目,所以坚持使用C++03。g++版本:4.8.4)
这个问题真的应该是 "Why doesn't boost::tie
work with boost::ptr_map
(or rather the result of dereferencing its iterator)?" -- BOOST_FOREACH
在这一切中是很无辜的。
调查
如果我们查看 version history of Boost,我们可以看到 Tuple 出现在版本 1.24.0 和 Pointer Container在版本 1.33.0.
元组
相关元组相关代码在github:
- 最新发布:https://github.com/boostorg/tuple/blob/boost-1.64.0/include/boost/tuple/detail/tuple_basic.hpp
- 首次发布:https://github.com/boostorg/tuple/blob/boost-1.24.0/include/boost/tuple/detail/tuple_basic.hpp
研究代码,我们可以做出以下观察:
指针容器
相关指针容器相关代码在github:
- 最新发布:https://github.com/boostorg/ptr_container/blob/boost-1.64.0/include/boost/ptr_container/detail/map_iterator.hpp
- 第三次发布:https://github.com/boostorg/ptr_container/blob/boost-1.34.0/include/boost/ptr_container/detail/map_iterator.hpp
- 首次发布:https://github.com/boostorg/ptr_container/blob/boost-1.33.0/include/boost/ptr_container/detail/map_iterator.hpp
研究代码,我们可以做出以下观察:
- 在前两个版本 (1.33.x) 中,解引用迭代器为我们提供了对值 [1] [2]
的引用
- 从第三个版本 (1.34.0) 开始,我们得到一个
ref_pair
,有点像 std::pair
,但实际上不是
[1]
[2]
[3]
结论
我们可以通过一次迭代来消除BOOST_FOREACH
,但仍然会得到同样的错误:
boost::tie(one, two) = *int2strMap.begin();
根据我们之前学到的知识,我们知道这等同于
boost::tuple<int&, std::string*&>(one, two) = *int2strMap.begin();
我们还知道 *int2strMap.begin()
将导致 std::string
引用或 ref_pair
.
由于元组没有可以采用其中任何一个的赋值运算符,因此建议的代码段无法与任何现有版本的 Boost 一起编译。
解决方法
从 boost::tuple
和 boost::tie
的实现中获得灵感,我们可以编写一个简单的 reference_pair
模板,它包含两个引用并允许分配任何看起来像 [=35] 的东西=](即具有成员 first
和 second
),以及将创建 reference_pair
.
实例的辅助函数 tie
示例代码
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace {
template<class T0, class T1>
struct reference_pair
{
T0& first;
T1& second;
reference_pair(T0& t0, T1& t1) : first(t0), second(t1) {}
template<class U>
reference_pair& operator=(const U& src) {
first = src.first;
second = src.second;
return *this;
}
};
template<class T0, class T1>
inline reference_pair<T0, T1> tie(T0& t0, T1& t1)
{
return reference_pair<T0, T1>(t0, t1);
}
}
int main()
{
boost::ptr_map<int, std::string> int2strMap;
int n(0);
int2strMap.insert(n, new std::string("one"));
int2strMap.insert(++n, new std::string("two"));
int2strMap.insert(++n, new std::string("three"));
int one;
std::string* two;
BOOST_FOREACH(tie(one, two), int2strMap)
{
std::cout << one << " " << *two << std::endl;
}
}
控制台输出
0 one
1 two
2 three
我想使用 BOOST_FOREACH
迭代 boost::ptr_map
,结果遇到了 this neat-looking solution。与给出的其他解决方案相比,我更愿意使用它来提高可读性。我写了下面的代码:
boost::ptr_map<int, std::string> int2strMap;
int x = 1;
int2strMap.insert(x, new std::string("one"));
int one;
std::string* two;
BOOST_FOREACH(::boost::tie(one, two), int2strMap)
{
std::cout << one << two << std::endl;
}
但是,编译失败,并出现以下错误(完整的错误消息还有几行,如果我应该粘贴它们请告诉我。):
error: no match for 'operator=' (operand types are 'boost::tuples::detail::tie_mapper<int, std::basic_string<char>*, void, void, void, void, void, void, void, void>::type {aka boost::tuples::tuple<int&, std::basic_string<char>*&, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>}' and 'boost::iterators::iterator_reference<boost::ptr_map_iterator<std::_Rb_tree_iterator<std::pair<const int, void*> >, int, std::basic_string<char>* const> >::type {aka boost::ptr_container_detail::ref_pair<int, std::basic_string<char>* const>}')
BOOST_FOREACH(::boost::tie(one, two), int2strMap)
建议的解决方案似乎适用于少数人,我无法弄清楚为什么它对我不起作用。我在这里做错了什么?
(注意:我正在做一个史前项目,所以坚持使用C++03。g++版本:4.8.4)
这个问题真的应该是 "Why doesn't boost::tie
work with boost::ptr_map
(or rather the result of dereferencing its iterator)?" -- BOOST_FOREACH
在这一切中是很无辜的。
调查
如果我们查看 version history of Boost,我们可以看到 Tuple 出现在版本 1.24.0 和 Pointer Container在版本 1.33.0.
元组
相关元组相关代码在github:
- 最新发布:https://github.com/boostorg/tuple/blob/boost-1.64.0/include/boost/tuple/detail/tuple_basic.hpp
- 首次发布:https://github.com/boostorg/tuple/blob/boost-1.24.0/include/boost/tuple/detail/tuple_basic.hpp
研究代码,我们可以做出以下观察:
指针容器
相关指针容器相关代码在github:
- 最新发布:https://github.com/boostorg/ptr_container/blob/boost-1.64.0/include/boost/ptr_container/detail/map_iterator.hpp
- 第三次发布:https://github.com/boostorg/ptr_container/blob/boost-1.34.0/include/boost/ptr_container/detail/map_iterator.hpp
- 首次发布:https://github.com/boostorg/ptr_container/blob/boost-1.33.0/include/boost/ptr_container/detail/map_iterator.hpp
研究代码,我们可以做出以下观察:
- 在前两个版本 (1.33.x) 中,解引用迭代器为我们提供了对值 [1] [2] 的引用
- 从第三个版本 (1.34.0) 开始,我们得到一个
ref_pair
,有点像std::pair
,但实际上不是 [1] [2] [3]
结论
我们可以通过一次迭代来消除BOOST_FOREACH
,但仍然会得到同样的错误:
boost::tie(one, two) = *int2strMap.begin();
根据我们之前学到的知识,我们知道这等同于
boost::tuple<int&, std::string*&>(one, two) = *int2strMap.begin();
我们还知道 *int2strMap.begin()
将导致 std::string
引用或 ref_pair
.
由于元组没有可以采用其中任何一个的赋值运算符,因此建议的代码段无法与任何现有版本的 Boost 一起编译。
解决方法
从 boost::tuple
和 boost::tie
的实现中获得灵感,我们可以编写一个简单的 reference_pair
模板,它包含两个引用并允许分配任何看起来像 [=35] 的东西=](即具有成员 first
和 second
),以及将创建 reference_pair
.
tie
示例代码
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace {
template<class T0, class T1>
struct reference_pair
{
T0& first;
T1& second;
reference_pair(T0& t0, T1& t1) : first(t0), second(t1) {}
template<class U>
reference_pair& operator=(const U& src) {
first = src.first;
second = src.second;
return *this;
}
};
template<class T0, class T1>
inline reference_pair<T0, T1> tie(T0& t0, T1& t1)
{
return reference_pair<T0, T1>(t0, t1);
}
}
int main()
{
boost::ptr_map<int, std::string> int2strMap;
int n(0);
int2strMap.insert(n, new std::string("one"));
int2strMap.insert(++n, new std::string("two"));
int2strMap.insert(++n, new std::string("three"));
int one;
std::string* two;
BOOST_FOREACH(tie(one, two), int2strMap)
{
std::cout << one << " " << *two << std::endl;
}
}
控制台输出
0 one
1 two
2 three