我想创建一个带有变量引用的boost融合向量。目标是将函数传递给各种参数并将它们添加到融合矢量中。由于引用类型,我使用TMP一次添加一个元素。但有时融合向量中的某些元素是错误的。它似乎是未定义的行为(错误的值,读取访问冲突) 我写了一个例子,其中我'展开'在TMP中使用的递归以便于理解。它只是添加两个融合向量的引用并输出结果:
#include <iostream>
#include <boost/ref.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container.hpp>
using namespace boost;
using namespace boost::fusion;
//add second element
template <typename T>
vector<int&, double&> createVector2(T vec, double& v2) {
auto newVector = join(vec, make_vector(ref(v2)));
return newVector;
}
//add first element
template <typename T>
vector<int&, double&> createVector(T vec, int& v1, double& v2) {
auto newVector = join(vec, make_vector(ref(v1)));
return createVector2(newVector, v2);
}
int main() {
int v1 = 10;
double v2 = 15.3;
vector<> vec;
auto ret = createVector(vec, v1, v2);
std::cout << at_c<0>(ret) << std::endl;
std::cout << at_c<1>(ret) << std::endl;
if (at_c<0>(ret) != v1) {
std::cout << "FAILED" << std::endl;
}
if (at_c<1>(ret) != v2) {
std::cout << "FAILED" << std::endl;
}
return 0;
}
当访问boost融合向量中的引用(读取访问冲突)时,程序崩溃,首先在此行中:
std::cout << at_c<0>(ret) << std::endl;
我使用VC11作为编译器(版本17.00.51106.1)。该错误仅在发布模式下。但是当我使用VC10,GCC 4.7.0或GCC 4.7.2时,没有错误,程序运行正常 要使程序与VC11一起使用,我必须更改此行
auto newVector = join(vec, make_vector(ref(v1)));
到
auto newVector = as_vector(join(vec, make_vector(ref(v1))));
那么,上面的示例是否包含错误或VC11优化器有问题?是否允许传递本地boost融合视图(boost :: fusion :: join只返回一个视图,视图通过boost :: fusion :: vector转换为'normal'bool :: fusion :: vector)到另一个按价值运作?
答案 0 :(得分:1)
我在Microsoft connect(link)提交了一份错误报告。所以我的问题的答案是我的代码中存在错误。
问题是join函数返回一个boost fusion joint_view,它包含seq1和seq2这两个元素。它们被定义为:
template <typename Sequence1, typename Sequence2>
struct joint_view : sequence_base<joint_view<Sequence1, Sequence2> >
{
(...)
private:
typename mpl::if_<traits::is_view<Sequence1>, Sequence1, Sequence1&>::type seq1;
typename mpl::if_<traits::is_view<Sequence2>, Sequence2, Sequence2&>::type seq2;
};
我的代码的问题是我将一个临时对象(从make_vector返回)传递给join函数。增强融合矢量不是视图,seq1和seq2是参考。因此,join函数返回一个joint_view,其中包含对临时对象的引用,该引用无效。有两种修改可以解决这个问题:
第一个解决方案(对于createVector也是如此):
template <typename T>
vector<int&, double&> createVector2(T vec, double& v2) {
auto x = make_vector(ref(v2));
auto newVector = join(vec, x);
return newVector;
}
现在,join返回一个joint_view,其中包含对x的引用,该引用是有效的。最后,视图被转换为增强融合矢量,并且参考被解析。
第二个解决方案(对于createVector也一样):
template <typename T>
vector<int&, double&> createVector2(T vec, double& v2) {
return join(vec, make_vector(ref(v2)));
}
临时对象的生命周期(由make_vector返回)是整个return语句,与第一个版本一样,视图将转换为boost融合向量,并再次解析引用。
感谢Eric Brumer(微软)提供这两种解决方案。
<强>结论强>: 不要将临时对象传递给boost fusion join函数(仅当它是另一个视图时)。