【问题标题】:Can I give different behaviours to boost::proto::tag types?我可以为 boost::proto::tag 类型提供不同的行为吗?
【发布时间】:2017-04-06 11:44:32
【问题描述】:

我正在尝试使用 boost proto 懒惰地评估表达式,我想做的是能够为 +、-、函数等标签提供不同的行为。

function(
    terminal(8functionILi2EE)
  , plus(
        multiplies(
            terminal(6tensorILi0EE)
          , terminal(6tensorILi1EE)
        )
      , multiplies(
            terminal(6tensorILi2EE)
          , terminal(6tensorILi3EE)
        )
    )
)

对于像上面这样的树,我希望能够指定每个树节点的行为方式。

例如。

struct context : proto::callable_context< context const >
{

    // Values to replace the tensors
    std::vector<double> args;

    // Define the result type of the zero.
    // (This makes the zero_context "callable".)
    typedef double result_type;

    // Handle the tensors:
    template<int I>
    double operator()(proto::tag::terminal, tensor<I>) const
    {
        std::cout << this->args[I] << std::endl;
        return this->args[I];
    }

    template<int I>
    void operator()(proto::tag::plus) const
    {
        std::cout << " + " << std::endl;
    }

};

当我这样做时

double result = (_tensorA + _tensorB)(10, 20);

我希望我的输出是

10
+
20

但这只是

10
20

任何帮助将不胜感激! :)

【问题讨论】:

    标签: c++ boost proto


    【解决方案1】:
    template<int I>
    void operator()(proto::tag::plus) const
    {
        std::cout << " + " << std::endl;
    }
    

    模板参数I 是不可演绎的,因此重载永远不适用。删除模板参数:

    void operator()(proto::tag::plus) const
    {
        std::cout << " + " << std::endl;
    }
    

    但是你真正想要的是拦截二元运算符。好。注意它是二进制。所以它有两个参数:

    template<size_t I, size_t J>
    void operator()(proto::tag::plus, proto::literal<tensor<I>>&, proto::literal<tensor<J>>&) const {
        std::cout << " + " << std::endl;
    }
    

    Live On Coliru

    但是,这会阻止对表达式树的进一步评估。不是你想要的,对吧。所以,让我们做一个简单的重新实现:

    template<size_t I, size_t J>
    double operator()(proto::tag::plus, proto::literal<tensor<I>>& a, proto::literal<tensor<J>>& b) const {
        auto va = (*this)(proto::tag::terminal{}, a.get());
        std::cout << " + " << std::endl;
        auto vb = (*this)(proto::tag::terminal{}, b.get());
        return va + vb;
    }
    

    Live On Coliru

    请通用

    但是,有件事告诉我你想要通用表达式。所以t1 + (t2 + t3) 也应该可以工作,但(t2 + t3) 不是字面意思...

    让我们通过委托来简化:

    template<typename A, typename B>
    double operator()(proto::tag::plus, A& a, A& b) const {
        auto va = proto::eval(a, *this);
        std::cout << " + " << std::endl;
        auto vb = proto::eval(b, *this);
        return va + vb;
    }
    

    完整样本

    Live On Coliru

    #include <boost/proto/proto.hpp>
    #include <vector>
    
    namespace proto = boost::proto;
    
    template <size_t N> struct tensor { };
    template <size_t N, size_t M> tensor<N+M> operator+(tensor<N>, tensor<M>) { return {}; }
    
    struct context : proto::callable_context< context const >
    {
        using base_type = proto::callable_context<context const>;
    
        // Values to replace the tensors
        std::vector<double> args { 0, 111, 222, 333 };
    
        // Define the result type of the zero.
        // (This makes the zero_context "callable".)
        typedef double result_type;
    
        // Handle the tensors:
        template<size_t I>
        double operator()(proto::tag::terminal, tensor<I>) const
        {
            std::cout << this->args[I] << std::endl;
            return this->args[I];
        }
    
        template<typename A, typename B>
        double operator()(proto::tag::plus, A& a, B& b) const {
            auto va = proto::eval(a, *this);
            std::cout << " + " << std::endl;
            auto vb = proto::eval(b, *this);
            return va + vb;
        }
    };
    
    int main() {
        proto::literal<tensor<1> > t1;
        proto::literal<tensor<2> > t2;
        proto::literal<tensor<3> > t3;
        auto r = proto::eval(t1 + (t2 + t3), context());
        std::cout << "eval(t1 + (t2 + t3)) = " << r << "\n";
    }
    

    打印

    111
     + 
    222
     + 
    333
    eval(t1 + (t2 + t3)) = 666
    

    【讨论】:

    • 非常感谢!这正是我所需要的。 :)
    • 不客气。另请参阅this。欢迎来到 SO!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多