问题
Firstly, apologies for the similarity to my previous question here, but I don't think I asked the right thing.
I have a method:
template <typename T>
void some_method( T &t)
{...}
which takes a type fusion::vector<T1, T2, T3, ..., Tn>
to be determined at runtime - e.g. vector<int, double>
in one call and vector<int, double, int>
in another.
I want to fill this vector dynamically with something like:
int blah = 5;
for(int i = 0; i<size(t); i++){
at_c<i>(t) = blah;
}
This doesn't work since at_c expects a const
.
I've tried other stuff (see the previous question) but still can't work out how to achieve this.
Any help much appreciated! Thanks.
回答1:
As @Mankarse specified correctly, you can't use fusion
containers in a for
loop and that's because fusion
containers are all about tuple
and each element may have different type from other elements, all functions that iterate through a fusion
container are actually a couple of functions and usually implemented as template
or overloaded functions. So in order to initialize a fusion
container from a vector
you should have multiple functions (or simply a template that will be compiled to multiple classes or functions) that all have access to that vector(or at least an iterator from the vector
and an state variable that can increased for each call). So you have 2 options:
1) Use 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) Write a function that recursively call itself with next item of the container(remember syntax of this function is like recursive functions but it is not recursive at all):
// 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>() );
}
As you see second case is much more complicated, but if you understand its logic you can use it to do anything with fusion
containers, so the choice is all yours!!
回答2:
You could use 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);
}
In an attempt to demystify the for_each
, here is some mostly equivalent code that uses numerical indices instead:
#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);
}
回答3:
How about this?
This is similar to the above case using boost::fusion::for_each .
But faster when i < size(t) than the above.
usage
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
}
body
#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;}
This is copy of boost-users ML my post http://lists.boost.org/boost-users/2012/08/75493.php http://d.hatena.ne.jp/niitsuma/20120803/1343979718
来源:https://stackoverflow.com/questions/13096239/how-to-fill-boostfusionvector-at-runtime