当使用带有std :: map和自定义向量空间代数的boost odeint时,没有可行的重载'='

时间:2017-10-25 01:01:51

标签: c++ c++11 boost odeint

我正在尝试使用std :: maps解决一个ODE系统,并使用boost的odeint。默认情况下不支持std :: map,因此我按照the boost documentation中的相关步骤定义了自定义向量空间代数。

在编译时,我收到以下错误:

In file included from /usr/local/include/boost/numeric/odeint.hpp:32:
In file included from /usr/local/include/boost/numeric/odeint/stepper/runge_kutta_dopri5.hpp:25:
In file included from /usr/local/include/boost/numeric/odeint/stepper/base/explicit_error_stepper_fsal_base.hpp:31:
/usr/local/include/boost/numeric/odeint/util/copy.hpp:43:12: error: no viable overloaded '='
        to = from;

...

note: candidate function not viable: 'this' argument has type 'const DeterministicStateType', but method is not marked const
DeterministicStateType& operator=(const DeterministicStateType& a)

我不是C ++专家,但这似乎意味着=方法需要是const,这对我来说没有意义。

MWE:

#include <iostream>
#include <map>
#include <boost/numeric/odeint.hpp>
#include <boost/operators.hpp>

namespace pl = std::placeholders;

class DeterministicStateType :
    boost::additive1< DeterministicStateType ,
    boost::additive2< DeterministicStateType , double ,
    boost::multiplicative2< DeterministicStateType , double > > >
{
public:
    DeterministicStateType(std::map<std::string, double> map) : mMap(map)
    {}

    DeterministicStateType() {}

    DeterministicStateType(const DeterministicStateType &p)
    {
        DeterministicStateType(p.mMap);
    }

    std::map<std::string, double> mMap;

    DeterministicStateType& operator+=(const DeterministicStateType &p)
    {
        for (std::map<std::string, double>::const_iterator it = p.mMap.begin(); it != p.mMap.end(); it++)
        {
            mMap[it->first] = mMap[it->first] + it->second;
        }

        return *this;
    }

    DeterministicStateType& operator+=(double a)
    {
        for (std::map<std::string, double>::const_iterator it = mMap.begin(); it != mMap.end(); it++)
        {
            mMap[it->first] += a;
        }

        return *this;
    }

    DeterministicStateType& operator*=(const double a)
    {
        for (std::map<std::string, double>::const_iterator it = mMap.begin(); it != mMap.end(); it++)
        {
            mMap[it->first] *= it->second;
        }

        return *this;
    }

    DeterministicStateType& operator=(const DeterministicStateType& a)
    {
        mMap.clear();
        std::map<std::string, double> map2 = a.mMap;
        for (std::map<std::string, double>::iterator it = map2.begin() ; it != map2.end(); it++)
        {
            mMap[it->first] = it->second;
        }

        return *this;
    }        
};

DeterministicStateType operator/( const DeterministicStateType &p1 , const DeterministicStateType &p2 )
{
    std::map<std::string, double> map;
    std::map<std::string, double> p2map = p2.mMap;
    for (std::map<std::string, double>::const_iterator it = p1.mMap.begin() ; it != p1.mMap.end() ; it++)
    {
        map[it->first] = it->second / p2map[it->first];
    }
    return DeterministicStateType(map);
}

DeterministicStateType abs( const DeterministicStateType &p )
{
    std::map<std::string, double> map;
    for (std::map<std::string, double>::const_iterator it = p.mMap.begin() ; it != p.mMap.end() ; it++)
    {
        map[it->first] = std::abs(it->second);
    }
    return DeterministicStateType(map);
}

namespace boost { namespace numeric { namespace odeint {
    template<>
    struct vector_space_norm_inf< DeterministicStateType >
    {
        typedef double result_type;
        double operator()( const DeterministicStateType &p ) const
        {
            using std::abs;
            double max = 0;
            for (std::map<std::string, double>::const_iterator it = p.mMap.begin(); it != p.mMap.end(); it++)
            {
                if (abs(it->second) > max)
                {
                    max = abs(it->second);
                }
            }
            return max;
        }
    };
}}}

namespace boost { namespace numeric { namespace odeint {

    template< >
    struct is_resizeable<DeterministicStateType>
    {
        typedef boost::true_type type;
        const static bool value = type::value;
    };

    template< >
    struct same_size_impl<DeterministicStateType, DeterministicStateType>
    {
        static bool same_size(const DeterministicStateType &v1, const DeterministicStateType &v2)
        {
            return v1.mMap.size() == v2.mMap.size();
        }
    };

    template< >
    struct resize_impl<DeterministicStateType, DeterministicStateType>
    {
        static void resize(DeterministicStateType &v1, const DeterministicStateType &v2)
        {
            for (std::map<std::string, double>::const_iterator it = v2.mMap.begin() ; it != v2.mMap.end() ; it++)
            {
                if (v1.mMap.count(it->first) == 0)
                {
                    v1.mMap[it->first] = 0;
                }
            }
        }
    };
}}}

void derivative(const DeterministicStateType p, DeterministicStateType &dpdt, const double t) {}

using namespace boost::numeric::odeint;
int main(int argc, char *argv[])
{
    std::map<std::string, double> x0; x0["A"]=1.0; x0["B"]=1.0;
    typedef runge_kutta_dopri5<DeterministicStateType, double, DeterministicStateType, double, vector_space_algebra> stepper_type;
    integrate_adaptive( make_dense_output(1e-6, 1e-6, stepper_type()) ,
        derivative, DeterministicStateType(x0), 0.0, 300.0, 0.00001);
}

1 个答案:

答案 0 :(得分:1)

您复制赋值运算符将rhs视为非常量

DeterministicStateType &operator=(DeterministicStateType &a) {

当源是调用代码中的const时,这不是必需的,也不会编译。只需通过添加const:

来修复它
DeterministicStateType &operator=(DeterministicStateType const& a) {

<击>

更好的是,简化所有这些功能(我认为乘法完全是错误的,它甚至没有使用它的论点):

State &operator=(State const&a) {
    mMap = a.mMap;
    return *this;
}

更好的是,假设您已在编译器上启用C ++ 11:

State &operator=(State const&a) = default;

等待为什么我的错误信息仍在此处?

那是因为现在你仍然将临时传递给integrate_adaptive。临时工具仅与const&绑定,永不与&²绑定。因此,只需在通话前创建DeterministicStateType,然后通过引用传递,而不是临时DeterministicStateType(x0)

int main() {
    DeterministicStateType x0 { { {"A", 1.0}, {"B", 1.0} } };
    typedef runge_kutta_dopri5<DeterministicStateType, double, DeterministicStateType, double, vector_space_algebra>
        stepper_type;
    integrate_adaptive(make_dense_output(1e-6, 1e-6, stepper_type()), derivative, x0, 0.0,
                       300.0, 0.00001);
}

简化代码

在这个简化版本中,我使用了一个名称空间,使mMap变为私有,并使用了C ++ 11的特性,使一切变得不那么容易出错:

<强> Live On Wandbox

#include <boost/numeric/odeint.hpp>
#include <boost/operators.hpp>
#include <iostream>
#include <map>

namespace Deterministic {

    class State : boost::additive1<State,
                      boost::additive2<State, double, 
                          boost::multiplicative2<State, double> > >
    {
      public:
        using Map = std::map<std::string, double>;
        State(Map const& map) : mMap(map) {}
        State() = default;
        State(const State &p) = default;
        State &operator=(State const&a) = default;

        State &operator+=(const State &p) {
            for (auto& p : p.mMap) mMap[p.first] += p.second;
            return *this;
        }

        State &operator+=(double a) {
            for (auto& p : mMap)
                p.second += a;
            return *this;
        }

        State &operator*=(double f) {
            for (auto& p : mMap) mMap[p.first] *= f;
            return *this;
        }

        friend State abs(const State &p) {
            using std::abs;
            auto map = p.mMap;

            for(auto& e : map)
                e.second = abs(e.second);

            return map;
        }

        friend State operator/(const State &p1, const State &p2) {
            auto map = p1.mMap;

            for(auto& e : map)
                e.second /= p2.mMap.at(e.first);

            return map;
        }

        friend double vector_space_norm_inf_impl(State const& p) {
            double max = 0;
            using std::abs;
            for (auto& el : p.mMap)
                max = std::max(abs(el.second), max);
            return max;
        }

        size_t size() const { return mMap.size(); }

        void resize(State const& other) {
            for (auto& el : other.mMap)
                mMap[el.first] += 0; // inserts if non-existent
        }

      private:
        Map mMap;
    };
}

using DeterministicStateType = Deterministic::State;

namespace boost { namespace numeric { namespace odeint {
    template <> struct vector_space_norm_inf<DeterministicStateType> {
        typedef double result_type;
        double operator()(const DeterministicStateType &p) const { return vector_space_norm_inf_impl(p); }
    };

    template <> struct is_resizeable<DeterministicStateType> {
        typedef boost::true_type type;
        const static bool value = type::value;
    };

    template <> struct same_size_impl<DeterministicStateType, DeterministicStateType> {
        static bool same_size(const DeterministicStateType &v1, const DeterministicStateType &v2) {
            return v1.size() == v2.size();
        }
    };

    template <> struct resize_impl<DeterministicStateType, DeterministicStateType> {
        static void resize(DeterministicStateType &v1, const DeterministicStateType &v2) {
            v1.resize(v2);
        }
    };
} } }

void derivative(const DeterministicStateType, DeterministicStateType &, const double) {}

using namespace boost::numeric::odeint;

int main() {
    DeterministicStateType x0 { { {"A", 1.0}, {"B", 1.0} } };
    typedef runge_kutta_dopri5<DeterministicStateType, double, DeterministicStateType, double, vector_space_algebra>
        stepper_type;
    integrate_adaptive(make_dense_output(1e-6, 1e-6, stepper_type()), derivative, x0, 0.0,
                       300.0, 0.00001);
}

²除了破坏的编译器