如何在运行时填充boost::fusion::vector?

6
首先,对于我的上一个问题(链接)的相似之处,我表示歉意,但我认为我没有问对问题。
我有一个方法:
template <typename T>
void some_method( T &t)
{...}

这段代码接受一个类型为fusion::vector<T1, T2, T3, ..., Tn>的参数,在运行时决定 - 例如在一次调用中是vector<int, double>,在另一次调用中是vector<int, double, int>

我想要动态地向这个向量中填充一些东西,例如:

int blah = 5;
for(int i = 0; i<size(t); i++){
at_c<i>(t) = blah;
}

这个无法正常工作,因为 at_c 函数需要一个 const 参数。

我尝试了其他方法(请参见以前的问题),但仍然无法找到实现这一目标的方法。

非常感谢任何帮助!谢谢。


什么是blah?直接使用for循环永远不会起作用,因为在每次迭代中,blah必须具有不同的类型(您需要编写递归模板函数)。您能提供一些表示要插入的值的方式的示例吗? - Mankarse
我假设将要插入的值将被适当地转换为正确的类型。为了举例说明,你可以想象blah是一个int - arlogb
它们不会在运行时确定,而是在编译时确定。 - K-ballo
3个回答

6
正如@Mankarse所指出的那样,您不能在for循环中使用fusion容器,因为fusion容器涉及元组,每个元素可能与其他元素具有不同的类型。遍历fusion容器的所有函数实际上都是成对的函数,并且通常是作为模板或重载函数实现的。因此,为了从向量初始化fusion容器,您应该拥有多个函数(或简单地编译为多个类或函数的模板),它们都可以访问该向量(或至少是来自向量的迭代器和可以增加每次调用的状态变量)。所以您有两个选择:

1)使用boost :: fusion :: fold:

template< class StdIteratorT >
struct initialize_fusion_container_from_std_iterator {
    typedef StdIteratorT    result_type;

    template< class T >
    StdIteratorT operator()( StdIteratorT i, T& val ) {
        val = *i;
        return ++i;
    }
};
void use_fold_demo() {
    int p1[] = {4, 5, 6};
    fusion::vector<int, double, int> fv;
    std::vector<int> sv2( p1, p1 + _countof(p1) );
    fusion::fold( fv, sv2.begin(),
    initialize_fusion_container_from_std_iterator<std::vector<int>::iterator>() );
}

2) 编写一个函数,该函数以容器的下一项递归调用自身(请记住,此函数的语法类似于递归函数,但实际上并不是递归的):

// this will be called when we reach end of the fusion container(FIBeginT==FIEndT)
template< class FIBeginT, class FIEndT, class StdIteratorT >
void set_fusion_iterator( FIBeginT b, FIEndT e, StdIteratorT i, boost::mpl::true_ )
{
}
// this will be called when FIBeginT != FIEndT
template< class FIBeginT, class FIEndT, class StdIteratorT >
void set_fusion_iterator( FIBeginT b, FIEndT e, StdIteratorT i, boost::mpl::false_ )
{
    *b = *i;
    set_fusion_iterator( fusion::next(b), e, ++i,
        fusion::result_of::equal_to<
            typename fusion::result_of::next<FIBeginT>::type, FIEndT >() );
}

void recursive_function_demo() {
    typedef fusion::vector<int, double, int>    my_fusion_vector;

    int p1[] = {1, 2, 3};
    std::vector<int> sv1( p1, p1 + _countof(p1) );
    fusion::vector<int, double, int> fv;
    set_fusion_iterator( fusion::begin(fv), fusion::end(fv), sv1.begin(),
        fusion::result_of::equal_to<
            typename fusion::result_of::end<my_fusion_vector>::type,
            typename fusion::result_of::begin<my_fusion_vector>::type>() );
}

正如您所看到的,第二种情况更加复杂,但如果您理解其逻辑,就可以使用它来处理任何与fusion容器相关的事情,所以选择权在于您!


3
你可以使用boost::fusion::for_each进行操作:

链接

#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container.hpp>

struct F {
    F(int blah): blah(blah){}
    template <typename T>
    void operator()(T& t) const {
        t = blah;
    }
    int blah;
};

template <typename T>
void some_method(T &t)
{
    boost::fusion::for_each(t, F(6));
}

int main() {
    boost::fusion::vector<int, double, int> idi;
    some_method(idi);
    boost::fusion::vector<int, double> id;
    some_method(id);
}

为了让“for_each”更易理解,这里提供了一些使用数字索引的基本等效代码:
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>

template<typename T, int N, int End>
struct some_method_impl {
    void operator()(T& t) const {
        int blah = 6;
        boost::fusion::at_c<N>(t) = blah;
        some_method_impl<T, N+1, End>()(t);
    }
};

template<typename T, int N>
struct some_method_impl<T,N,N> {
    void operator()(T& t) const {}
};


template <typename T>
void some_method(T &t)
{
    some_method_impl<T,0,boost::fusion::result_of::size<T>::type::value>()(t);
}

int main() {
    boost::fusion::vector<int, double, int> idi;
    some_method(idi);
    boost::fusion::vector<int, double> id;
    some_method(id);
}

非常有帮助。实际上,你说得很对,我应该更具体地说明 blah…… 它是一个 vector<int>,我想将这个 blah 中的值映射到 fusion::vector 中。使用你提出的方法可以实现吗? - arlogb
1
@arlogb:是的,使用 zip 函数将序列与一组索引一起压缩,并在 for_each 过程中使用这些索引来对向量进行索引。 - Mankarse

0

这个怎么样?

这与上面使用 boost::fusion::for_each 相似。

但是当 i < size(t) 时比上面更快。

用法:

main(){
  boost::fusion::vector<int,double,std::string,char> vec(9 ,2.2 ,"aaa" ,'b');
  std::cout << at_n_dynamic<double>(vec, 1) << std::endl; //=> 2.2
}

正文

#include <boost/fusion/include/vector.hpp>    
template<typename V>
struct fusion_at_n_functor
{
   mutable int i;
   int n;
   mutable V value;
   fusion_at_n_functor(int _n):i(0),n(_n){}
   void operator()(const V & t) const
   { if(i==n){value=t;} i++;}  
   template<typename T>
   void operator()(const T & t) const
   { i++;}
};

template <typename First,typename Last,typename AtN > void
at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::true_ ){}
template <typename First,typename Last,typename AtN > void
at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::false_ ){  
  if(atn.i == atn.n ){atn(boost::fusion::deref(i));}
  else{
    atn(boost::fusion::deref(i));
    at_n_dynamic_fusion_impl(boost::fusion::next(i),last,atn,
           boost::fusion::result_of::equal_to<
             typename boost::fusion::result_of::next<First>::type,Last>  ());}
}

template <typename Ret,typename Sequence>  Ret
 at_n_dynamic(Sequence & seq, int n){ 
   fusion_at_n_functor<Ret> atn(n);
#if 0 
  // enabling this if is same to the above case of boost::fusion::for_each 
   boost::fusion::for_each(seq, atn);
#else
  // this recursion loop stop at n. but boost::fusion::for_each stop at last
   at_n_dynamic_fusion_impl(boost::fusion::begin(seq),boost::fusion::end(seq) ,atn,
         boost::fusion::result_of::equal_to<
           typename boost::fusion::result_of::begin<Sequence>::type,
           typename boost::fusion::result_of::end<Sequence>::type>());    
#endif
    return atn.value;}

这是我在boost-users邮件列表中发布的帖子的副本http://lists.boost.org/boost-users/2012/08/75493.phphttp://d.hatena.ne.jp/niitsuma/20120803/1343979718


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接