I'm trying to make a grammar in Boost.Proto that matches a vector type, but when I give it a terminal of that type, it doesn't match the grammar. The type definition looks like this:
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];
};
The grammar I'm trying to get to match looks something like this:
namespace proto = boost::proto;
using proto::_;
using proto::N;
struct test:
proto::terminal<vector<_, N> >
{};
The match fails:
int main ()
{
BOOST_MPL_ASSERT((proto::matches<proto::terminal<vector<float, 2> >::type, test>));
}
How do I make a grammar that matches a specific type?
EDIT:
It appears that proto::_ and proto::N is not being used as a wildcard in custom types. The code does compile with this grammar (the matches
assertion passes):
struct test:
proto::terminal<vector<float, 2> >
{};
But does not work when either one of the wildcards are in the type:
struct test:
proto::terminal<vector<float, N> >
{};
Or:
struct test:
proto::terminal<vector<_, 2> >
{};
So if I can't use the wildcards my own types, how can I test if the expression is a terminal containing a vector?
To compare the type within a terminal to a type, you can use type traits. I have some traits structs set up that evaluate to true if the given type is a vector:
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_
{};
And then you can put this in your grammar:
proto::and_<
proto::terminal<_>,
proto::if_<is_vector<proto::_value>()>
>
I've tried this approach before, but the reason it didn't work was because I forward declared vector<...> in the wrong namespace in the header the traits structs were in.
Boost.Proto doesn't work with non-type template parameters. If you can, change your vector type to use integral type wrappers, like this:
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];
};
Then you should be able to match as follows:
int main ()
{
BOOST_MPL_ASSERT((proto::matches<
proto::terminal<vector<float, mpl::int_<2> > >::type,
proto::terminal<vector<_, _> >
>));
}
Hope that helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With