boost::fusion::map 允许重复键
boost::fusion::map allows duplicate keys
根据boost::fusion::map docs:
对于每个键,映射最多可以包含一个元素。
在实践中,很容易违反这一点。
我能够定义以下类型:
using map_type = fusion::map<
fusion::pair<int, char>
, fusion::pair<int, char>
, fusion::pair<int, char>>;
并使用以下重复键实例化它:
map_type m(
fusion::make_pair<int>('X')
, fusion::make_pair<int>('Y')
, fusion::make_pair<int>('Z'));
使用 fusion::for_each
遍历映射显示数据结构确实包含 3 对,每个键的类型为 int
:
struct Foo
{
template<typename Pair>
void operator()(const Pair& p) const
{
std::cout << typeid(typename Pair::first_type).name() << "=" << p.second << 'n';
}
};
fusion::for_each(m, Foo {});
输出:
i=X
i=Y
i=Z
我本来希望对密钥唯一性static_assert
,但显然并非如此。
这是为什么呢?
如何确保没有人可以使用重复的密钥实例化
fusion::map
?
完整工作示例:(在大肠杆菌上)
#include <boost/fusion/container.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <iostream>
namespace fusion = ::boost::fusion;
struct Foo
{
template<typename Pair>
void operator()(const Pair& p) const
{
std::cout << typeid(typename Pair::first_type).name() << "=" << p.second << 'n';
}
};
int main()
{
using map_type = fusion::map<
fusion::pair<int, char>
, fusion::pair<int, char>
, fusion::pair<int, char>>;
map_type m(
fusion::make_pair<int>('X')
, fusion::make_pair<int>('Y')
, fusion::make_pair<int>('Z'));
fusion::for_each(m, Foo {});
return 0;
}
由于下面的评论,这里有一些关于我实际想要实现的目标的进一步细节。
这个想法是自动生成FIX序列化代码。
给定的字段类型在任何给定的FIX消息中只能存在一次 - 因此需要static_assert
激励示例:(关于大肠杆菌)
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/mpl/transform.hpp>
#include <iostream>
namespace fusion = ::boost::fusion;
namespace mpl = ::boost::mpl;
template<class Field>
struct MakePair
{
using type = typename fusion::result_of::make_pair<Field, typename Field::Type>::type;
};
template<class Fields>
struct Map
{
using pair_sequence = typename mpl::transform<Fields, MakePair<mpl::_1>>::type;
using type = typename fusion::result_of::as_map<pair_sequence>::type;
};
///////////////////////////
template<typename... Fields>
class Message
{
public:
template<class Field>
void set(const typename Field::Type& val)
{
fusion::at_key<Field>(_fields) = val;
}
void serialise()
{
fusion::for_each(_fields, Serialiser {});
}
private:
struct Serialiser
{
template<typename Pair>
void operator()(const Pair& pair) const
{
using Field = typename Pair::first_type;
std::cout << Field::Tag << "=" << pair.second << "|";
}
};
using FieldsVector = fusion::vector<Fields...>;
using FieldsMap = typename Map<FieldsVector>::type;
FieldsMap _fields;
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
"message must be constructed from unique types"); // this assertion doesn't work
};
///////////////////////////
#define MSG_FIELD(NAME, TYPE, TAG)
struct NAME
{
using Type = TYPE;
static const int Tag = TAG;
};
MSG_FIELD(MsgType, char, 35)
MSG_FIELD(Qty, int, 14)
MSG_FIELD(Price, double, 44)
using Quote = Message<MsgType, Qty, Price>;
///////////////////////////
int main()
{
Quote q;
q.set<MsgType>('a');
q.set<Qty>(5);
q.set<Price>(1.23);
q.serialise();
return 0;
}
从关联容器的文档:
。不检查键的唯一性。
正如理查德·霍奇斯(Richard Hodges)所暗示的那样,这可能是设计使然。
这static_assert不是每次遇到几何模板扩展时都涉及几何模板扩展吗?
尽管如此,可以使用boost::mpl
将提供给fusion::map
的序列简化为唯一的序列,并且static_assert
序列长度相同。
首先,我们创建一个结构,该结构遍历类型列表并创建一系列唯一类型
// given a sequence, returns a new sequence with no duplicates
// equivalent to:
// vector UniqueSeq(vector Seq)
// vector newSeq = {}
// set uniqueElems = {}
// for (elem : Seq)
// if (!uniqueElems.find(elem))
// newSeq += elem
// uniqueElems += elem
// return newSeq
template<class Seq>
struct UniqueSeq
{
using type = typename mpl::accumulate<
Seq,
mpl::pair<typename mpl::clear<Seq>::type, mpl::set0<> >,
mpl::if_<
mpl::contains<mpl::second<mpl::_1>, mpl::_2>,
mpl::_1,
mpl::pair<
mpl::push_back<mpl::first<mpl::_1>, mpl::_2>,
mpl::insert<mpl::second<mpl::_1>, mpl::_2>
>
>
>::type::first;
};
然后我们更改Map
的定义,以使用 UniqueSeq::type
生成pair_sequence
:
// given a sequence of fields, returns a fusion map which maps (Field -> Field's associate type)
template<class Fields>
struct Map
{
using unique_fields = typename UniqueSeq<Fields>::type;
using pair_sequence = typename mpl::transform<unique_fields, MakePair<mpl::_1>>::type;
using type = typename fusion::result_of::as_map<pair_sequence>::type;
};
因此,给定一个字段列表,我们可以创建一个fusion::vector
和一个fusion::map
,其结果为 UniqueSeq<Fields>
,并断言每个字段的大小相同:
using FieldsVector = fusion::vector<Fields...>;
using FieldsMap = typename Map<FieldsVector>::type;
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
"message must be constructed from unique types");
传递重复的字段现在会导致编译错误:
静态断言失败:消息必须从唯一类型构造
scratch/main.cpp: In instantiation of ‘class Message<Qty, Price, Qty>’:
scratch/main.cpp:129:23: required from here
scratch/main.cpp:96:5: error: static assertion failed: message must be constructed from unique types
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
^
关于科里鲁的完整示例
这不是答案(OP 已经提供了答案),而是对澄清我的一些评论的请求的回应。
实现关键唯一性的一种方法是通过原始 mpl 使用。例如,将FIX消息作为我们的域,以下代码段应该说明这个想法。该代码未编译并仅作为通用说明示例提供。
template <class ValueType, int FieldTag>
struct FixField {
using value_t = ValueType;
static const short tag = FieldTag;
};
using CumQty = FixField<double, 14>;
using Price = FixField<double, 44>;
using inherit = boost::mpl::inherit<boost::mpl::placeholders::_1, boost::mpl::placeholders::_2>;
template <class list>
using inherit_linearly = boost::mpl::inherit_linearly<list, inherit>::type;
template <class Members>
struct FixMessage : iherit_linearly<Members> {
using members_t = Members;
template <class T> T& get() { return static_cast<T&>(*this); } // const ver as well
};
struct ExecutionReport : public FixMessage<boost::mpl::set<CumQty, Price> > {
static constexpr char const* name = "ExecutionReport";
};
现在,您已经拥有了所需的所有内省执行报告。您可以使用 boost::mpl::for_each
轻松序列化它,也可以反序列化任何消息并获得强类型的 FixMessage。
我不确定如果您两次使用相同的类型,您是否会收到编译错误,但我相信您在迭代时只会看到一次该类型。
- C/C++编译器通常会删除重复的库吗
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 整数不会重复超过随机数
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 从包含m行的文件中提取n行,必要时(惰性地)重复该文件
- 使用通用值初始化 std::map,不重复
- 如何使用 MAP C++ 删除重复项
- 使用STD :: MAP在数据及其性能问题中查找重复项.我可以预先分配吗?
- 如何计算C++中非重复值的数量 std::map<Key,Values>
- 使用 stl::map 和 stl::unordered_map 对包含大量重复元素的数组数据进行排序
- 检查与MAP中的密钥关联的重复值
- 检查字符串是否使用STD :: MAP包含重复
- C++ std::map 或 std::set - 有效地插入重复项
- 使用 std::map 从数组中删除重复项
- std::multiset vs. std::<int>map<int, std::size_t> 用于保留多个可重复的整数值
- boost::fusion::map 允许重复键
- 使用map++计算重复项
- c++中std::map中的Const char *重复数据
- std::map 不删除带有自定义对象的重复项