3

I'm using Boost 1.49, OpenCV 2.3.1, CMake 2.8 in a C++ project.

I'm building two executables with the same header file, one for production and the other for testing. The contest.hpp file specifies:

namespace boost
{
   namespace serialization 
   {

   template<class Archive>
   void serialize(Archive& ar, cv::Point& p, const unsigned int version);

   template<class Archive>
   void serialize(Archive& ar, cv::Rect_<int>& r, const unsigned int version);

   template<class Archive>
   void serialize(Archive& ar, cv::Size_<int>& s, const unsigned int version);
   }
}

and these are implemented in contest.cpp file like

namespace boost
{
    namespace serialization
    {

    template<class Archive>
    void serialize(Archive& ar, cv::Point& p, const unsigned int version)
    {
        ar & p.x;
        ar & p.y;
    }

    template<class Archive>
    void serialize(Archive& ar, cv::Rect_<int>& r, const unsigned int version)
    {
        ar & r.x;
        ar & r.y;
        ar & r.height;
        ar & r.width;
    }

    template<class Archive>
    void serialize(Archive& ar, cv::Size_<int>& s, const unsigned int version)
    {
        ar & s.width;
        ar & s.height;
    }

    }
}

And test-contest.cpp mundanely tests these like

    BOOST_AUTO_TEST_CASE(Serialization1)
{

Point point_write(3, 5);
{
    ofstream point_file("Point.txt");
    ar::text_oarchive point_archive(point_file);
    sr::serialize(point_archive, point_write, 0);
}
Point point_read(0, 0);
{
    ifstream point_file("Point.txt");
    ar::text_iarchive point_archive(point_file);
    sr::serialize(point_archive, point_read, 0);
}
BOOST_CHECK(point_read == point_write);


Rect rect_write(3, 5, 1, 7);
{
    ofstream rect_file("Rect.txt");
    ar::text_oarchive rect_archive(rect_file);
    sr::serialize(rect_archive, rect_write, 0);
}
Rect rect_read(0, 0, 0, 0);
{
    ifstream rect_file("Rect.txt");
    ar::text_iarchive rect_archive(rect_file);
    sr::serialize(rect_archive, rect_read, 0);
}
BOOST_CHECK((rect_read.x) == (rect_write.y) && (rect_read.y) == (rect_write.y));

Size size_write(3, 5);
{
    ofstream size_file("Size.txt");
    ar::text_oarchive size_archive(size_file);
    sr::serialize(size_archive, size_write, 0);
}
Size size_read(0, 0);
{
    ifstream size_file("Size.txt");
    ar::text_iarchive size_archive(size_file);
    sr::serialize(size_archive, size_read, 0);
}
BOOST_CHECK(size_read == size_write);
}

where sr and ar are defined in common.hpp like

namespace ar = ::boost::archive;
namespace sr = ::boost::serialization;

The makefiles are produced from CMake configuration like:

link_directories(${DEPENDENCY_DIR}/libboost/lib)
link_directories(${DEPENDENCY_DIR}/libopencv/lib)

add_executable(test-contest test-contest.cpp contest.cpp)
add_executable(contest main.cpp contest.cpp)

target_link_libraries(test-contest boost_serialization opencv_core opencv_highgui opencv_imgproc boost_program_options boost_unit_test_framework boost_filesystem)

target_link_libraries(contest boost_serialization opencv_core opencv_highgui opencv_imgproc boost_program_options boost_filesystem)

so, the moral of the story is, both contest and test-contest are compiled and linked against the same header and libraries. Note that other Boost libraries are linked and tested successfully.

When it comes to make after cmake 'Unix Makefiles' .., for contest it says

[ 40%] Building CXX object CMakeFiles/contest.dir/main.cpp.o
[ 60%] Building CXX object CMakeFiles/contest.dir/contest.cpp.o
Linking CXX executable contest
[ 60%] Built target contest

but for test-contest

[ 80%] Building CXX object CMakeFiles/test-contest.dir/test-contest.cpp.o
[100%] Building CXX object CMakeFiles/test-contest.dir/contest.cpp.o
Linking CXX executable test-contest
CMakeFiles/test-contest.dir/test-contest.cpp.o: In function `otap::TPageImage::Serialization1::test_method()':
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:119: undefined reference to `void boost::serialization::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive&, cv::Rect_<int>&, unsigned int)'
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:125: undefined reference to `void boost::serialization::serialize<boost::archive::text_iarchive>(boost::archive::text_iarchive&, cv::Rect_<int>&, unsigned int)'
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:133: undefined reference to `void boost::serialization::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive&, cv::Size_<int>&, unsigned int)'
/home/iesahin/Repository/otapexplorer/cli/contest-2012/test-contest.cpp:139: undefined reference to `void boost::serialization::serialize<boost::archive::text_iarchive>(boost::archive::text_iarchive&, cv::Size_<int>&, unsigned int)'
collect2: ld returned 1 exit status
make[2]: *** [test-contest] Error 1

And IMHO the weirdest part is, there are no errors for serialize(Archive, cv::Point, int) which is from the same header/library in OpenCV with serialize(Archive, cv::Rect_<int>, int) or cv::Size_<int>. Their serialization/test functions are almost identically defined.

I'm linking these serialize functions from contest.cpp file successfully. I tried replacing Rect with Rect_<int> in the definitions, to no change. I tried changing the order of libraries in CMakeLists.txt and took boost_serialization from the end to its current place, to no avail.

Where am I doing it wrong?

Emre Sahin
  • 468
  • 4
  • 14

1 Answers1

2

I think you need the implementations of your three serialize functions moved from contest.cpp to contest.hpp.

For the reasons why, see Why can templates only be implemented in the header file? or Why should the implementation and the declaration of a template class be in the same header file?

Community
  • 1
  • 1
Fraser
  • 74,704
  • 20
  • 238
  • 215