Соответствие грамматике Boost.Proto типу
Я пытаюсь создать грамматику в Boost.Proto, которая соответствует векторному типу, но когда я даю ему терминал этого типа, он не соответствует грамматике. Определение типа выглядит так:
template <typename T, unsigned D>
struct vector
{
typedef T scalar;
enum { size = D };
scalar& operator[](unsigned i)
{
return m_components[i];
}
scalar const& operator[](unsigned i) const
{
return m_components[i];
}
private:
scalar m_components[size];
};
Грамматика, которую я пытаюсь найти, выглядит примерно так:
namespace proto = boost::proto;
using proto::_;
using proto::N;
struct test:
proto::terminal<vector<_, N> >
{};
Матч не удался:
int main ()
{
BOOST_MPL_ASSERT((proto::matches<proto::terminal<vector<float, 2> >::type, test>));
}
Как мне сделать грамматику, которая соответствует определенному типу?
РЕДАКТИРОВАТЬ:
Похоже, что proto:: _ и proto:: N не используются в качестве подстановочных знаков в пользовательских типах. Код компилируется с этой грамматикой (matches
утверждение проходит):
struct test:
proto::terminal<vector<float, 2> >
{};
Но не работает, когда один из подстановочных знаков в типе:
struct test:
proto::terminal<vector<float, N> >
{};
Или же:
struct test:
proto::terminal<vector<_, 2> >
{};
Так что, если я не могу использовать подстановочные знаки своих собственных типов, как я могу проверить, является ли выражение терминалом, содержащим вектор?
2 ответа
Boost.Proto не работает с нетиповыми параметрами шаблона. Если вы можете, измените ваш векторный тип, чтобы использовать обертки целочисленного типа, например так:
template <typename T, typename D>
struct vector
{
typedef T scalar;
enum { size = D::value };
scalar& operator[](unsigned i)
{
return m_components[i];
}
scalar const& operator[](unsigned i) const
{
return m_components[i];
}
private:
scalar m_components[size];
};
Тогда вы должны быть в состоянии соответствовать следующим:
int main ()
{
BOOST_MPL_ASSERT((proto::matches<
proto::terminal<vector<float, mpl::int_<2> > >::type,
proto::terminal<vector<_, _> >
>));
}
Надеюсь, это поможет!
Чтобы сравнить тип в терминале с типом, вы можете использовать черты типа. У меня есть некоторые настроенные структуры черт, которые оценивают в true, если данный тип является вектором:
template <typename T>
struct is_vector:
boost::mpl::false_
{};
template <typename T, unsigned Size>
struct is_vector <dev::math::vector <T, Size> >:
boost::mpl::true_
{};
И тогда вы можете поместить это в вашей грамматике:
proto::and_<
proto::terminal<_>,
proto::if_<is_vector<proto::_value>()>
>
Я пробовал этот подход раньше, но причина, по которой он не работал, заключалась в том, что я перенаправил объявленный вектор<...> в неправильное пространство имен в заголовке, в котором находились структуры черт.