По boost::fusion::map документы:повышение :: фьюжн :: Карта позволяет дубликаты ключей
A map may contain at most one element for each key.
На практике это легко нарушить это.
Я могу определить следующий тип:
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
с дублирующими ключами?
Полный рабочий пример: (on coliru)
#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
мотивирующим пример: (on coliru)
#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;
}
Задать вопрос для boost :: fusion authors :) В любом случае, я действительно верю boost :: fusion теперь устарел. – SergeyA
не будет ли static_assert включать геометрическое расширение шаблона каждый раз, когда он встречается? –
@SergeyA вы можете предложить, что использовать вместо 'fusion', если он действительно устарел? –