c++ - boost.proto + 在构建表达式树之前检测无效终端

标签 c++ template-meta-programming boost-proto

我在玩 Boost.Proto,主要是为了好玩,看看将来我是否可以在我自己的项目中使用它。也就是说, 作为这个库的大多数初学者,我玩过“惰性 vector ”示例的修改版本,但使用转换而不是上下文来执行评估。 vector 定义如下(好吧,我知道,'vector' 不是在全局命名空间范围内定义的东西的好名字......)

template <std::size_t D, class T>
class vector { 
    T data_[D];
    enum { dimension = D };
    // Constructors, destructors...
};

// expression wrapper
template <class> class vector_expr;

它是在维度和数据类型上模板化的,有点像 boost::array(我没有使用它,因为我想重载 operator= 来接受表达式树,就像通常在这类事情中所做的那样)。我使用原型(prototype)手册中的代码定义了标量

// scalar = everything convertible to double
struct scalar_terminal :
    proto::terminal<proto::convertible_to <double> >
{};

// vector = everything for which the is_vector returns true_
template <class T> struct is_vector : mpl::false_ {};
template <std::size_t D, class T> struct is_vector <vector <D, T> > : mpl::true_ {};

struct vector_terminal :
    proto::and_ <
       proto::terminal<_>
     , proto::if_<is_vector<proto::_value>()>
  >
{};

// domain   
struct vector_domain
    : proto::domain <proto::generator <vector_expr> >
{};

// expression wrapper
template <class Expr>
struct vector_expr : proto::extends <Expr, vector_expr <Expr>, vector_domain>
{
    typedef proto::extends <Expr, vector_expr <Expr>, vector_domain> base_type;

    // Construct from expression (enough to compile)
    vector_expr (Expr const &e) : base_type (e) {}
};

// Bring in operators
BOOST_PROTO_DEFINE_OPERATORS(is_vector, vector_domain)

现在,我要做的第一件事是:检查表达式中的所有 vector 终端是否具有相同的 维度 D。我最终得到了以下工作代码

// a meta-function that returns the vector dimension
template <class T>
struct vector_dim
{
    typedef mpl::int_ <T::dimension> type;
};

// a meta-function that combines dimensions from subtrees. int<-1> means
// that sub-trees store vectors of differing static dimension. No good.
template <class D1, class D2>
struct dim_combine
{
   typedef mpl::int_ < -1 > type;
};

// ok, dimensions are the same, propagate up the value
template <class D>
struct dim_combine <D, D>
{
   typedef D type;
};

// 0 is used to mark scalars. It is ok to mix vectors and scalars
// but propagate up the vector dimension only. This is for vector
// on the left and scalar on the right.
template <class D>
struct dim_combine <D, mpl::int_ <0> >
{
   typedef D type;
};

// this is for scalar on the left, vector to the right of some 
// binary operator.
template <class D>
struct dim_combine <mpl::int_ <0>, D>
{
   typedef D type;
};

// need this too to avoid ambiguity between the two specializations
// above when D is int_ <0>. Even if this combination should never
// happen
template <>
struct dim_combine <mpl::int_ <0>, mpl::int_<0> >
{
   typedef mpl::int_<0> type;
};


// A transform that check that all arrays have the same dimension
struct vec_dim_check
    : proto::or_ <
        proto::when <
            vector_terminal
          , vector_dim<proto::_value>()
        >
      , proto::when <
            scalar_terminal
          , boost::mpl::int_<0>()
        >
      , proto::when <
            proto::nary_expr<_, proto::vararg<_> >
          , proto::fold<_, boost::mpl::int_<0>(), dim_combine<vec_dim_check, proto::_state>()>
        >
    >
{};

template <class E>
void check_dim (E const&)
{
    typedef typename boost::result_of<vec_dim_check(E)>::type type;
    BOOST_ASSERT(type::value == 3);
}

int main (int, char**)
{
    vector <3,double> a,b,c;
    check_dim (2*a+b/c);
    return 0;
}

问题是:既然数组的维度已经编码在表达式中,那么它应该 可以在编译时检测到无效组合。甚至应该可以避免 首先创建树。这是如何实现的?

提前致谢,致以最诚挚的问候

最佳答案

非常好。现在您需要定义一个只接受有效 vector 表达式的语法,如下所示:

struct vector_grammar_untyped
  : proto::or_<
        scalar_terminal,
        vector_terminal,
        proto::nary_expr<proto::_, proto::vararg<vector_grammar_untyped> >
    >
{};

struct vector_grammar
  : proto::and_<
        vector_grammar_untyped,
        proto::if_<mpl::not_equal_to< mpl::int_<-1>, vec_dim_check >()>
    >
{};

然后,您将 vector_domain 的定义更改如下:

struct vector_domain
    : proto::domain <proto::generator <vector_expr>, vector_grammar >
{};

这应该可以防止您创建未通过自定义类型检查的表达式。 proto::domain 的第二个模板参数是该域中所有表达式必须遵守的语法。

免责声明:以上代码未经测试,但它应该能让您朝着正确的方向前进。

关于c++ - boost.proto + 在构建表达式树之前检测无效终端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12114290/

相关文章:

c# - C++ 到 C# 桥接多个进程

c++ - 这是 "Tag Dispatching"吗?

c++ - 在编译时填充 std::set?

c++ - 从自动模板参数回调中提取参数

c++ - 模板化一个简单的 Boost Proto C++ 表达式计算器

c++ - 以非侵入式方式用表达式树替换自定义类型

c++ - 非默认构建的 boost::proto 终端

c++ - 如果没有带有 LANGUAGE CXX 的 set_source_files_properties,CMake 将无法构建

c++ - 在 std 算法中使用 std::move_iterator 并以 lambda 作为 pred 是否安全

c++ - 将继承类对象的 vector 传递给需要基类 vector 的函数