代码之家  ›  专栏  ›  技术社区  ›  Astor

C++17 constexpr数组矩阵和通过重载运算符兼容的函子

  •  1
  • Astor  · 技术社区  · 7 年前

    我试图通过使用容器使两种类型的对象兼容,为了使其更困难,我的代码必须能够在编译时进行计算。

    我的一个对象类型按以下方式构造为函子:

    template <std::size_t n,std::size_t p=1,typename number=double>
    class Oper{
        public:
        constexpr Oper(const number d_=1.):d(d_){}
        constexpr Oper(const Oper& oper_):d(oper_.d){}
        const number d ;
        constexpr auto operator()(const auto &v) const {
        typename std::remove_const<typename std::remove_reference<decltype(v)>::type>::type w{} ;
            /* Do some stuff to build w using v and d*/
        return w ;}
    };
    

    另一种对象类型只是 std::array<std::array<double,n>,n> ,即矩阵。

    这些对象具有以下作为自由函数的运算符:

    template <std::size_t nr, std::size_t nc>
    constexpr auto
    operator *(const std::array<std::array<double,nc>,nr> & A,
               const std::array<double,nc> & x){
        std::array<double,nr> res{};
        for (auto i=0u;i<nr;i++)
            for (auto j=0u;j<nc;j++)
                res[i] += A[i][j]*x[j];
        return res;
    }
    
    template <std::size_t nrA, std::size_t ncA, std::size_t nrB, std::size_t ncB>
    constexpr auto operator *(const std::array<std::array<double,ncA>,nrA> & A,
                              const std::array<std::array<double,ncB>,nrB> & B){
        std::array<std::array<double,ncB>,nrA> res{};
        for (auto k=0u;k<ncB;++k)
            for (auto i=0u;i<nrA;++i)
                for (auto j=0u;j<nrB;++j)
                    res[i][k] += A[i][j]*B[j][k];
        return res ;
    }
    
    constexpr auto operator *(const auto & A,const auto & x){
        return A(x) ;
    }
    

    请记住,我无法更改这些实现,它们是提供给我的。

    为了使这些操作符兼容,我创建了以下类

    constexpr auto id = [](const auto v) {return v;};
    
    template <typename Op, typename Preop=decltype(id)>
    class Cont{
    public:
        constexpr Cont(const Op & op_,const Preop & preop_=id):op(op_),preop(preop_){}
        constexpr Cont(const Cont & cont_):op(cont_.op),preop(cont_.preop){}
        const Op op ;
        const Preop preop ;
        template <typename Op2, typename Preop2>
        constexpr auto operator()(const Cont<Op2,Preop2> & mfop) const{
            return Cont<const Cont<Op,Preop>,const Cont<Op2,Preop2>>
                   (Cont(op,preop),mfop);}
        constexpr auto operator()(const auto & v) const{return op*(preop*v);}
    };
    

    这样,下面的主要代码就可以按预期编译和运行了

    int main(){
        const std::array<double,4> v{};
        const Cont A(Oper<4,1>(1.));
        const Cont B(std::array<std::array<double,4>,4>{std::array<double,4>{}});
        constexpr auto res = B*B*A*A*B*A*B*v;
        return 0;
    }
    

    门闩示例 here .

    我对这个问题有意见 Cont 班

    1. 关于 继续 当只使用函子(不使用数组)时,就是以某种方式将对应于不同函子的代码一个接一个地放置,理想情况下,优化整个链。这能实现吗?我该怎么做?也许是完美的转发魔法?

    2. 有许多复制品正在制作中 继续 ,这会导致编译器占用大量内存(GCC 8.2.0,带标志) -std=c++1z -fconcepts -Ofast )当要求进行完整的编译时计算时。我相信这是因为所有的拷贝都是在把操作员放在一起时执行的。这可能吗?有没有办法避免复制?

    0 回复  |  直到 7 年前
    推荐文章