我正在努力寻找我正在寻找的一小部分功能。
我有一个包含fusion::map
的课程。我想使用一个可变参数构造函数初始化该映射中的元素。
我希望最简单的方法是从构造函数参数构造fusion::vector
,然后在地图上调用for_each
,并将每个对的值设置为向量中对应的元素。
但是,为了做到这一点,我需要根据密钥类型计算该对的索引。 (pair::first_type
)
任何人都可以帮助我吗?
请参阅下面的示例代码:
#include <iostream>
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/fusion/include/has_key.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/mpl/transform.hpp>
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
// given a field, returns a fusion pair of <field, field::type>
template<class field>
struct make_pair
{
typedef typename fusion::result_of::make_pair<field, typename field::type>::type type;
};
// given a sequence of fields, returns a fusion map which maps field -> field::type
template<class... fields>
struct make_map
{
typedef typename boost::fusion::vector<fields...> vector;
typedef typename mpl::transform<vector, make_pair<mpl::_1>>::type pair_sequence;
typedef typename fusion::result_of::as_map<pair_sequence>::type type;
};
// initialise each member of a map with the corresponding element in the vector
template<typename vector>
struct init
{
init(vector& v) : _v(v) {}
template <typename pair>
void operator()(pair const& data) const
{
// TODO: use pair::first_type to find the index of this pair in the map, and set
// data.second to at_c<index>(_v);
}
vector& _v;
};
struct field1 { typedef int type; };
struct field2 { typedef int type; };
struct my_map
{
template<typename... args>
my_map(args... a)
{
typedef typename boost::fusion::vector<args...> vector;
vector arg_vec(a...);
fusion::for_each(_map, init<vector>(arg_vec));
}
typedef typename make_map<field1, field2>::type map;
map _map;
};
struct print
{
template <typename pair>
void operator()(pair const& data) const
{
std::cout << data.second << " ";
}
};
int main()
{
my_map m(1, 2);
fusion::for_each(m._map, print()); // should print '1 2'
return 0;
}
答案 0 :(得分:1)
答案 1 :(得分:1)
为我自己的问题添加另一个答案,这次是针对参数数量小于或等于地图中元素数量的用例。
以下是一个有效的解决方案:
#include <iostream>
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/fusion/include/has_key.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/fusion/include/copy.hpp>
#include <boost/fusion/include/begin.hpp>
#include <boost/fusion/include/next.hpp>
#include <boost/fusion/include/key_of.hpp>
#include <boost/fusion/iterator/key_of.hpp>
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
// given a field, returns a fusion pair of <field, field::type>
template<class field>
struct make_pair
{
typedef typename fusion::result_of::make_pair<field, typename field::type>::type type;
};
// given a sequence of fields, returns a fusion map which maps field -> field::type
template<class... fields>
struct make_map
{
typedef typename fusion::result_of::as_map<typename mpl::transform<boost::fusion::vector<fields...>, make_pair<mpl::_1>>::type>::type type;
};
//-------------------------------------------------------------------------------------------
// iterate through a fusion map to find the index of a given key
template<typename iter, typename key_type, typename seek_type>
struct key_index
{
typedef typename fusion::result_of::next<iter>::type next_iter;
typedef typename fusion::result_of::key_of<next_iter>::type next_key;
enum { value = 1 + key_index<next_iter, next_key, seek_type>::value };
};
template<typename iter, typename seek_type>
struct key_index<iter, seek_type, seek_type>
{
enum { value = 0 };
};
//-------------------------------------------------------------------------------------------
// copy an element from a vector to a map, if the index in the vector exists
template<typename map, typename vector, int index, bool in_vec>
struct do_copy
{
template<typename T>
void operator()(const vector& v, const T& dest)
{
const_cast<T&>(dest) = fusion::at_c<index>(v);
}
};
template<typename map, typename vector, int index>
struct do_copy<map, vector, index, false>
{
template<typename T>
void operator()(const vector&, const T&)
{ }
};
//-------------------------------------------------------------------------------------------
// initialise a map with the corresponding elements in a vector, vector may be smaller than the map
template<typename vector, typename map>
struct init
{
init(const vector& v) : _v(v) {}
template <typename pair> void operator()(const pair& data) const
{
typedef typename fusion::result_of::begin<map>::type begin_iter;
typedef typename fusion::result_of::key_of<begin_iter>::type key_type;
enum { index = key_index<begin_iter, key_type, typename pair::first_type>::value };
enum { in_vec = fusion::result_of::size<vector>::type::value > index };
do_copy<map, vector, index, in_vec>()(_v, data.second);
}
private:
const vector& _v;
};
//-------------------------------------------------------------------------------------------
struct field1 { typedef std::string type; };
struct field2 { typedef int type; };
struct field3 { typedef double type; };
struct field4 { typedef std::string type; };
struct field5 { typedef int type; };
struct field6 { typedef double type; };
struct my_map
{
template<typename... args>
my_map(args... a)
{
typedef typename fusion::vector<args...> vector;
fusion::for_each(_map, init<vector, map>(vector(a...)));
}
typedef typename make_map<field1, field2, field3, field4, field5, field6>::type map;
map _map;
};
struct print
{
template <typename pair>
void operator()(pair const& data) const
{
std::cout << data.second << " ";
}
};
//-------------------------------------------------------------------------------------------
int main()
{
my_map m("hello world", 5, 2.4);
fusion::for_each(m._map, print());
std::cout << std::endl;
return 0;
}