c++boostvisual-studio-2019visual-studio-2008-sp1

Problem using boost::object_pool boost version 1.56 with visual studio 2019


I am trying to convert boost::object_pool usage on my old project to new visual studio 2019 project, I am using boost version 1.56

ObjectPool.h

class BOOST_OBJECT_POOL_CHECKER
{
  boost::object_pool< T > m_sObjectPool;
  
  template <class Arg1>
  T* contruct(Arg1& sArg1)
  {
     T* temp = m_sObjectPool.construct(sArg1);
     return temp;
  }
}

MaterialServer.h

class MaterialServer
{
   MaterialServer(dword serviceType, std::string path);
   Material* NEW_MATERIAL();
}

Material.h

class Material
{
  BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;

  Material(MaterialServer* pMatServer);
  
}

Material.cpp

Material* MaterialServer::NEW_MATERIAL()
{
   //Material* returnMaterial = m_poolMATERIAL.construct(this); << error on vs2019, not correct parameter
   Material* returnMaterial = m_poolMATERIAL.construct(*this);
}

got first error

boost_1_56\boost\pool\detail\pool_construct_simple.ipp(19,1): error C2664: 'Material::Material(MaterialServer*)': cannot convert argument 1 from 'const T0' to 'MaterialServer *'
ObjectPool.h(68): message : see reference to function template instantiation 'Material *boost::object_pool<T,boost::default_user_allocator_new_delete>::construct<Arg1>(const T0 &)' being compiled
        with
        [
            T=Material,
            Arg1=MaterialServer,
            T0=MaterialServer
        ]

should I need upgrade boost version? because previously this code compiled fine on vs2008, but not compiled on vs2019, this c++11 standard so confusing for me

can I get explanation this behavior?


Solution

  • Frankly, this code cannot have compiled under any compiler.

    Note: I'm ignoring numerous typos, omitted semi-colons, omitted template declarators, typedefs and access specifiers to focus on the real issues.

    You're passing *this which is Material&. However, the contruct [sic] function takes a MaterialServer*.

    So, in fact, the commented line was closer, and makes sense IFF it were a member of MaterialServer, not Material.

    It would make a lot more sense, logically, for the material server to "create new materials", anyways, and almost works:

    class Material {
      public:
        Material(MaterialServer* pMatServer);
    };
    
    class MaterialServer {
        BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
    
      public:
        MaterialServer(dword serviceType, std::string path);
        Material* NEW_MATERIAL();
    };
    
    Material* MaterialServer::NEW_MATERIAL()
    {
        Material* returnMaterial = m_poolMATERIAL.construct(this);
        return returnMaterial;
    }
    

    I say /almost/ because construct takes its argument by mutable reference. That won't compile here (this is NOT a mutable lvalue).

    So, fixing that:

    template <typename Arg1> T* construct(Arg1 sArg1) {
        return m_sObjectPool.construct(sArg1);
    }
    

    Or, more generically:

    template <typename... Arg> T* construct(Arg&&... sArg) {
        return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
    }
    

    We get "compiling code". We can't link it (the constructors aren't defined).

    Adding some more imagined code:

    Live On Coliru

    #include <boost/pool/object_pool.hpp>
    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <atomic>
    
    using dword = uint32_t;
    
    template <typename T> class BOOST_OBJECT_POOL_CHECKER {
        boost::object_pool<T> m_sObjectPool;
    
      public:
        template <typename... Arg> T* construct(Arg&&... sArg)
        {
            return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
        }
    };
    
    class MaterialServer; // forward declare
    
    class Material {
      public:
        Material(MaterialServer* pMatServer);
    };
    
    class MaterialServer {
        BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
    
        dword _serviceType;
        std::string _path;
    
      public:
        MaterialServer(dword serviceType, std::string path)
            : _serviceType(serviceType)
            , _path(path)
        {
        }
    
        Material* NEW_MATERIAL();
    
        dword getServiceType() const { return _serviceType; }
        std::string_view getPath() const { return _path; }
    };
    
    Material* MaterialServer::NEW_MATERIAL()
    {
        Material* returnMaterial = m_poolMATERIAL.construct(this);
        return returnMaterial;
    }
    
    Material::Material(MaterialServer* pMatServer)
    {
        static std::atomic_int id{0};
        std::cout << "Material " << id++ << " from server ("
                  << pMatServer->getServiceType() << ", "
                  << std::quoted(pMatServer->getPath()) << ")\n";
    }
    
    int main() {
        MaterialServer a(123, "Material/a/resource");
        MaterialServer b(234, "Material/b/resource");
    
        a.NEW_MATERIAL();
        a.NEW_MATERIAL();
        b.NEW_MATERIAL();
        a.NEW_MATERIAL();
    }
    

    Prints

    Material 0 from server (123, "Material/a/resource")
    Material 1 from server (123, "Material/a/resource")
    Material 2 from server (234, "Material/b/resource")
    Material 3 from server (123, "Material/a/resource")