【问题标题】:Storing expression template functors存储表达式模板函子
【发布时间】:2010-03-19 10:22:14
【问题描述】:

目前,我对表达式模板非常感兴趣,并希望编写一个库来编写和区分具有 lambda 样式语法的数学函数。目前,我可以写(_x * _x)(2);并得到正确的结果4。但我真的很想做MathFunction f = _x * _x; f(2);之类的事情,但我对如何处理递归表达式模板没有任何想法在右侧。是否可以在不使用“auto”关键字而不是 MathFunction 或必须使 operator() 虚拟的情况下实现这一点?

感谢您的帮助!

【问题讨论】:

    标签: c++ templates expression


    【解决方案1】:

    .

    template<class T, class R>
    struct MathFuncBase
    {
       virtual R operator()(const T & v) = 0;
       virtual ~MathFuncBase() {}
    };
    
    tempate<class T, class R, class Func>
    struct MathFunc : MathFuncBase<T, R>
    {
       MathFunc(Func func) : func(func) {}
       virtual R operator()(const T & v) {
           return func(v);           
       }
    private:
       Func func;
    };
    
    tempate<class T, class R, class Func>
    boost::shared_ptr<MathFuncBase<T, R> > GetMathFunc(Func func) {
        return boost::shared_ptr<MathFuncBase<T, R> >(new MathFunc<T, R, Func> (func));
    }
    
    int main () {
        boost::shared_ptr<MathFuncBase<int, int> > f = GetMathFunc<int,int> (_x * _x);
        return (*f)(2);   
    }
    

    【讨论】:

    • MathFuncBase 析构函数对于您的用例应该是虚拟的。否则,当shared_ptr 超出范围时,它将具有未定义的行为。
    • 虚拟析构函数很好。但在shared_ptr 的情况下,不需要它。检查这个。
    • 我猜你的意思是提供一个在某处丢失的参考......无论如何,使用shared_ptr你可以提供你自己的删除器作为构造函数的参数,但在上面的代码块中你是不提供。如果您不向shared_ptr 构造函数提供第二个参数,则在销毁时它将根据存储的指针(MathFuncBase)的类型调用delete。在这种特殊情况下,UB 很可能不会有任何(坏)效果(基础对象和派生对象都不包含任何成员或执行任何初始化或销毁),但它仍然是 UB。
    • @David Rodríguez:on destruction it will call delete on the type of the stored pointer 不正确。在销毁时,它将对作为第一个参数(MathFunc,不是基类)传递的模板指针的类型调用 delete。检查一下。
    • boost::shared_ptr 的执行中来回花费了几分钟后,你是对的。我有错误的想法。如果我被允许,我会再次投票赞成这个答案:) 感谢您指出。
    【解决方案2】:

    嗯,Boost 已经支持这个功能,所以你可能想看看他们是如何做到的。

    以下链接对我学习很有帮助:
    http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Expression-template
    http://www.angelikalanger.com/Articles/Cuj/ExpressionTemplates/ExpressionTemplates.htm http://www.flipcode.com/archives/Faster_Vector_Math_Using_Templates.shtml

    第二个链接是我个人最喜欢的!

    一切顺利。

    【讨论】:

    • 感谢您的回答和链接!我已经扫描了 Boost.Lambda 文档以找到解决我的问题的方法,但我没有找到那些 lambda 函数实际上是“存储”的行,它们总是内联使用。目前,我使用“C++ Templates - The Definite Guide”方法来表达模板。
    • 未捕获的异常,我是建议你看看源代码。你已经看过了吗?
    【解决方案3】:

    实际上,我认为没有一种简单的方法来存储它们。如果我想创建 boost::lambda 表达式的命名实例,我会将结果分配给,比如说,int,然后从编译器的错误消息中复制所需类型的名称:

    #include <boost/lambda/lambda.hpp>
    
    int main()
    {
        using namespace boost::lambda;
        //int x = _1 + _2;
        boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<
        boost::lambda::arithmetic_action<boost::lambda::plus_action>, 
        boost::tuples::tuple<boost::lambda::lambda_functor<boost::lambda::placeholder<1> >, 
        boost::lambda::lambda_functor<boost::lambda::placeholder<2> >, 
        boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, 
        boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, 
        boost::tuples::null_type, boost::tuples::null_type> > > x = _1 + _2;
    }
    

    在现实生活中,您更有可能将它们存储在一个可以进行类型擦除的类型中,例如 boost::function

    #include <boost/lambda/lambda.hpp>
    #include <boost/function.hpp>   
    int main()
    {
        using namespace boost::lambda;
        boost::function<int(int, int)> x = _1 + _2;
        return x(-1, 1);
    }
    

    【讨论】:

      【解决方案4】:

      我怀疑如果没有虚函数这是可能的。您需要进行类型擦除,因为您不能使用 auto 和类似的。但是稍后在该范围内,由于您在类型擦除的对象上调用函数,因此您需要运行时支持来调用派生类对象上的函数。

      我怀疑如果没有auto,您将无法做到这一点。

      【讨论】:

        【解决方案5】:

        由于我是这个网站的新手,直到我提交了这个问题,我才找到this。感谢您的回答,但这正是我真正想要的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-16
          • 1970-01-01
          相关资源
          最近更新 更多