添加对boost :: fusion :: vector的引用

时间:2013-01-13 15:00:38

标签: c++ visual-c++ boost-fusion

我想创建一个带有变量引用的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)到另一个按价值运作?

1 个答案:

答案 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,其中包含对临时对象的引用,该引用无效。有两种修改可以解决这个问题:

  1. 第一个解决方案(对于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的引用,该引用是有效的。最后,视图被转换为增强融合矢量,并且参考被解析。

  2. 第二个解决方案(对于createVector也一样):

    template <typename T>
    vector<int&, double&> createVector2(T vec, double& v2) {
        return join(vec, make_vector(ref(v2)));
    }
    

    临时对象的生命周期(由make_vector返回)是整个return语句,与第一个版本一样,视图将转换为boost融合向量,并再次解析引用。

  3. 感谢Eric Brumer(微软)提供这两种解决方案。

    <强>结论: 不要将临时对象传递给boost fusion join函数(仅当它是另一个视图时)。