2

我正在尝试让一些(迄今为止)Windows 代码在 unix 机器上编译,但在以下方法中遇到了一些错误:

namespace EDIN {
    void World::Save(char const filename[])                                                  
    {                                                                                        
        std::ofstream ofs(filename);                                                         

        boost::archive::text_oarchive oa(ofs);                                               

        oa << this << cellSequence << report; // line 590: error!
    }
}

错误如下所示:

test.cpp:在成员函数'void EDIN::World::Save(const char*)'中:test.cpp:122:12:错误:'operator<<'不匹配(操作数类型是'boost::archive ::text_oarchive' 和 'EDIN::World*') oa << this << cellSequence << report; // 第 590 行:错误!^ test.cpp:122:12:注意:候选人是:在 /home/armanschwarz/lib/boost_1_55_0/boost/archive/detail/common_oarchive.hpp:22:0 包含的文件中,来自 /home/armanschwarz/lib/boost_1_55_0 /boost/archive/basic_text_oarchive.hpp:32,来自 /home/armanschwarz/lib/boost_1_55_0/boost/archive/text_oarchive.hpp:31,来自 test.cpp:1:/home/armanschwarz/lib/boost_1_55_0/boost/archive /detail/interface_oarchive.hpp:62:15: 注意:存档& boost::archive::detail::interface_oarchive::operator<<(T& ) [与 T = EDIN::World*; Archive = boost::archive::text_oarchive] Archive & operator<<(T & t){ ^ /home/armanschwarz/lib/boost_1_55_0/boost/archive/detail/interface_oarchive.hpp:62:15:注意:没有已知的转换对于从 'EDIN::World*' 到 'EDIN::World*&' 的参数 1</p>

我正在使用 boost 1.55.0(与我在 Visual Studio 上编译时相同)。谁能发现我在这里做错了什么?

这是一个来自 sehe 的独立示例:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/valarray.hpp>
#include <chrono>

namespace EDIN
{
    struct Region
    {
        int id;
        Region(int id = 42) : id(id) {}

      private:
        friend class boost::serialization::access;
        template<class Archive> void serialize(Archive & ar, const unsigned int file_version)
        {
            ar & id;
        }
    };

    struct Scheme
    {
        std::string GetSchemeType() const { return "scheme_type_42"; }
    };


    class World
    {
        // dummy members to make it compile
        // will be different things of course
        int mass, epoch;
        std::chrono::system_clock::time_point _start;

        std::string report;
      public:
        std::vector<int> cellSequence; // for demo, public

        World(std::string&, EDIN::Region&, unsigned int&, const std::chrono::system_clock::time_point&)
            : mass(99), epoch(88), _start(std::chrono::system_clock::now()), report("Report101")
        {
            // TODO!
        }

        Region       Bounds() const { return Region();       }
        int          Epoch()  const { return epoch;          }
        EDIN::Scheme Scheme() const { return EDIN::Scheme(); }
        std::chrono::system_clock::time_point StartingWallTime() const {
            return _start;
        }

        World()
            : mass(99), epoch(88), _start(std::chrono::system_clock::now()), report("Report101")
        {
        }

        void Save(char const filename[]);
        static World* Load(char const filename[]);

        private:
            friend class boost::serialization::access;
            template<class Archive> void serialize(Archive & ar, const unsigned int file_version)
            {
                ar & mass & epoch;
            }
    };
}

namespace boost
{
    namespace serialization
    {
        template<class Archive>
        inline void save_construct_data(Archive & ar, EDIN::World const * t, unsigned const int file_version)
        {
            time_t const totalRunningTime = std::chrono::duration_cast<std::chrono::duration<time_t, std::milli>>(
                std::chrono::system_clock::now() - t->StartingWallTime()).count();

            EDIN::Region const bounds = t->Bounds();
            time_t const epoch = t->Epoch();

            std::string tmp = t->Scheme().GetSchemeType();
            ar
                << bounds
                << epoch
                << totalRunningTime 
                << tmp;
        }

        template<class Archive>
        inline void load_construct_data(Archive & ar, EDIN::World * t, const unsigned int file_version)
        {
            EDIN::Region bounds;
            unsigned epoch;
            time_t totalRunningTime;
            std::string schemeType;
            ar >>
                bounds >>
                epoch >>
                totalRunningTime >>
                schemeType;

            std::chrono::system_clock::time_point const startingWallTime =
                std::chrono::system_clock::now() - std::chrono::duration<time_t, std::milli>(totalRunningTime);

            ::new(t) EDIN::World(schemeType,bounds,epoch,startingWallTime);
        }
    }
}

#include <fstream>

namespace EDIN {
    void World::Save(char const filename[])
    {
        std::ofstream ofs(filename);

        boost::archive::text_oarchive oa(ofs);

        oa << this << cellSequence << report; // line 590: error!
    }

    World* World::Load(char const filename[])
    {
        World *world = 0;

        std::ifstream ifs("world.save");
        boost::archive::text_iarchive ia(ifs);

        ia >> world;
        ia >> world->cellSequence >> world->report;

        return world;
    }
}

int main()
{
    EDIN::World world;
    world.cellSequence.push_back(12345);
    world.cellSequence.push_back(-6767);
    world.Save("world.save");

    EDIN::World* restored = EDIN::World::Load("world.save");
    restored->Save("world2.save");

    delete restored;
}

在这里使用 GCC 4.8.1 和 Boost 1.55.0 编译得很好。我正在使用 GCC 4.9.0 并提升 1.55.0。

编辑:我发现了一个似乎有效的黑客:

问题似乎是 G++ 4.9 不想World::thisWorld*to 转换为World*&. 用以下方法替换该World::Save方法可以解决问题:

void World::Save(char const filename[])
{
    std::ofstream ofs(filename);

    boost::archive::text_oarchive oa(ofs);

    World* thisCopy = this;
    oa << thisCopy << cellSequence << report;
}

GCC 4.8.1 和 GCC 4.9 之间的行为似乎存在差异,导致后者无法编译,除非我创建this指针的副本。如果有人能指出为什么会发生这种情况,以及这是否是一个错误或预期的行为改变,那将不胜感激!

4

2 回答 2

3

您没有提供所有必要的信息。

这是一个基于您 /did/ 显示的示例代码的独立示例

如您所见,它运行良好。我认为可能造成麻烦的唯一重要编辑是:

std::string tmp = t->Scheme().GetSchemeType();
ar
    << bounds
    << epoch
    << totalRunningTime 
    << tmp;

// and the following (use of this as mutable reference, which some versions of GCC erronously accepted)

void SaveWorld(World* world, char const filename[])
{
    std::ofstream ofs(filename);
    boost::archive::text_oarchive oa(ofs);
    oa << world << world->cellSequence << world->report; // line 590: error!
}

问题是按值或按返回因为const&上下文中t指针也是 const 。但是,ar <<需要一个非常量引用** [1] **,所以它不应该编译。

尽管如此,MSVC 可能接受它的原因可能是因为 MSVC 有一个(邪恶的)非标准扩展,当绑定到一个非常量引用时,它可以延长临时对象的生命周期

我的演示应用程序显示了序列化和反序列化的实际效果:

int main()
{
    using namespace EDIN;
    std::unique_ptr<World> world(new World);

    world->cellSequence.push_back(12345);
    world->cellSequence.push_back(-6767);
    SaveWorld(world.get(), "world.save");

    world.reset(LoadWorld("world.save"));
    SaveWorld(world.get(), "world2.save");
}

而且您可以验证这一点world.saveworld2.save最终为您自己(也在coliru上)相同。

完整的 SSCCE 代码供参考:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/valarray.hpp>
#include <chrono>
#include <memory>

namespace EDIN
{
    struct Region
    {
        int id;
        Region(int id = 42) : id(id) {}

      private:
        friend class boost::serialization::access;
        template<class Archive> void serialize(Archive & ar, const unsigned int file_version)
        {
            ar & id;
        }
    };

    struct Scheme
    {
        std::string GetSchemeType() const { return "scheme_type_42"; }
    };


    class World
    {
        // dummy members to make it compile
        // will be different things of course
        int mass, epoch;
        std::chrono::system_clock::time_point _start;

        std::string report;
      public:
        std::vector<int> cellSequence; // for demo, public

        World(std::string&, EDIN::Region&, unsigned int&, const std::chrono::system_clock::time_point&)
            : mass(99), epoch(88), _start(std::chrono::system_clock::now()), report("Report101")
        {
            // TODO!
        }

        Region       Bounds() const { return Region();       }
        int          Epoch()  const { return epoch;          }
        EDIN::Scheme Scheme() const { return EDIN::Scheme(); }
        std::chrono::system_clock::time_point StartingWallTime() const {
            return _start;
        }

        World()
            : mass(99), epoch(88), _start(std::chrono::system_clock::now()), report("Report101")
        {
        }

        friend void SaveWorld(World* world, char const filename[]);
        friend World* LoadWorld(char const filename[]);

        private:
            friend class boost::serialization::access;
            template<class Archive> void serialize(Archive & ar, const unsigned int file_version)
            {
                ar & mass & epoch;
            }
    };
}

namespace boost
{
    namespace serialization
    {
        template<class Archive>
        inline void save_construct_data(Archive & ar, EDIN::World const * t, unsigned const int file_version)
        {
            time_t const totalRunningTime = std::chrono::duration_cast<std::chrono::duration<time_t, std::milli>>(
                std::chrono::system_clock::now() - t->StartingWallTime()).count();

            EDIN::Region const bounds = t->Bounds();
            time_t const epoch = t->Epoch();

            std::string tmp = t->Scheme().GetSchemeType();
            ar
                << bounds
                << epoch
                << totalRunningTime 
                << tmp;
        }

        template<class Archive>
        inline void load_construct_data(Archive & ar, EDIN::World * t, const unsigned int file_version)
        {
            EDIN::Region bounds;
            unsigned epoch;
            time_t totalRunningTime;
            std::string schemeType;
            ar >>
                bounds >>
                epoch >>
                totalRunningTime >>
                schemeType;

            std::chrono::system_clock::time_point const startingWallTime =
                std::chrono::system_clock::now() - std::chrono::duration<time_t, std::milli>(totalRunningTime);

            ::new(t) EDIN::World(schemeType,bounds,epoch,startingWallTime);
        }
    }
}

#include <fstream>

namespace EDIN {
    void SaveWorld(World* world, char const filename[])
    {
        std::ofstream ofs(filename);

        boost::archive::text_oarchive oa(ofs);

        oa << world << world->cellSequence << world->report; // line 590: error!
    }

    World* LoadWorld(char const filename[])
    {
        World *world = 0;

        std::ifstream ifs("world.save");
        boost::archive::text_iarchive ia(ifs);

        ia >> world;
        ia >> world->cellSequence >> world->report;

        return world;
    }
}

int main()
{
    using namespace EDIN;
    std::unique_ptr<World> world(new World);

    world->cellSequence.push_back(12345);
    world->cellSequence.push_back(-6767);
    SaveWorld(world.get(), "world.save");

    world.reset(LoadWorld("world.save"));
    SaveWorld(world.get(), "world2.save");
}

[1]出于晦涩的技术原因,超出此处的范围

于 2014-05-03T08:43:47.967 回答
0

在有人提出真正的解决方案之前,这与其说是一个黑客的答案。问题似乎是 G++ 4.9 不想World::thisWorld*to 转换为World*&. 用以下方法替换该World::Save方法可以解决问题:

void World::Save(char const filename[])
{
    std::ofstream ofs(filename);

    boost::archive::text_oarchive oa(ofs);

    World* thisCopy = this;
    oa << thisCopy << cellSequence << report;
}

GCC 4.8.1 和 GCC 4.9 之间的行为似乎存在差异,导致后者无法编译,除非我创建this指针的副本。如果有人能指出为什么会发生这种情况,以及这是否是一个错误或预期的行为改变,那将不胜感激!

于 2014-05-04T01:25:18.057 回答