unsure how to reference my new Factory properly

Hi , I am trying to leverage a project which implements connection pooling.. and customizing it for a custom connection type

source https://github.com/malikkirchner/connection-pool

I have successfully packaged the library this creates under namespace `cpool`, via conan.. now I also have written my customized Connection Pool .. but I am unclear how to instantiate it properly in my project code

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 2.8.12)
project(server_server)
add_compile_options(-std=c++17)

# Using the "cmake" generator
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

FILE ( GLOB THRIFT_GEN_SRC src/gen-cpp/*.cpp )
FILE ( GLOB TMA_API_SRC src/TMA-client/*.cpp )

add_executable(server_server src/TMAConnection.cpp src/server_server.cpp ${THRIFT_GEN_SRC} ${TMA_API_SRC} )
target_link_libraries(server_server pthread CONAN_PKG::connpool CONAN_PKG::thrift CONAN_PKG::TMAapi ) */



TMAConnection.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <connection-pool/pool.h>

class TMAConnection final : public cpool::Connection {
public:
    bool heart_beat() override { return connected; }

    bool is_healthy() override { return connected; }

    bool connect() override {
        connected = true;
        return connected;
    }

    void disconnect() override { connected = false; }

private:
    TMAConnection() = default;
    friend cpool::ConnectionPoolFactory<TMAConnection>;

    bool connected = false;
};

template <>
class cpool::ConnectionPoolFactory<TMAConnection> {
public:
    static std::unique_ptr<cpool::ConnectionPool > create( const std::uint16_t num_connections ) {
        std::vector< std::unique_ptr<cpool::Connection> > connections;
        for ( std::uint16_t k = 0; k < num_connections; ++k ) {
            // cannot use std::make_unique, because constructor is hidden
            connections.emplace_back( std::unique_ptr<TMAConnection>( new TMAConnection{} ) );
        }
        return std::unique_ptr<cpool::ConnectionPool>( new cpool::ConnectionPool{std::move( connections )} );
    }
};


TMAConnection.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <connection-pool/pool.h>

class TMAConnection final : public cpool::Connection {
public:
    bool heart_beat() override;
    bool is_healthy() override;
    bool connect() override ;
    void disconnect() override ;

private:
    TMAConnection();
    friend cpool::ConnectionPoolFactory<TMAConnection>;
    bool connected;
};

template <>
class cpool::ConnectionPoolFactory<TMAConnection> {
public:
    static std::unique_ptr< cpool::ConnectionPool > create( const std::uint16_t num_connections );
};


Main.cpp - this is where I attempt to instantiate the Connection Pool via the factory.. but it doesn't like it.. any idea why? or tips is greatly appreciated

1
2
3
4
5
6
7
8
9
10
11
12
#include <connection-pool/pool.h>
#include "TMAConnection.h"

class ServerHandler : public myserverIf {
 public:
   ServerHandler(int num_of_connections) {
 
   auto tma_conn_pool = cpool::ConnectionPoolFactory<TMAConnection>::create(4);
   }

...
}


the error I am getting when attempting to compile is this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build .

...
...
...
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/Dev/cpp-multithreading-in-action/multi_conn_TMA_thrift/Server/cpp_server/build_cmake
Scanning dependencies of target server_server
[ 14%] Building CXX object CMakeFiles/server_server.dir/src/server_server.cpp.o
[ 28%] Linking CXX executable bin/server_server
/usr/bin/ld: CMakeFiles/server_server.dir/src/server_server.cpp.o: in function `serverHandlerFactory::getHandler(apache::thrift::TConnectionInfo const&)':
server_server.cpp:(.text._ZN22serverHandlerFactory10getHandlerERKN6apache6thrift15TConnectionInfoE[_ZN22serverHandlerFactory10getHandlerERKN6apache6thrift15TConnectionInfoE]+0x5f): undefined reference to `cpool::ConnectionPoolFactory<TMAConnection>::create(unsigned short)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/server_server.dir/build.make:213: bin/server_server] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/server_server.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

Last edited on
undefined reference to `cpool::ConnectionPoolFactory<TMAConnection>::create(unsigned short)

Just like templates, template specializations also need to be in the 'header' (that is, full definition before being called) so that the full definition is known when the compiler generates code from a template.

Your template specialization for cpool::ConnectionPoolFactory<TMAConnection> is in a .cpp file so your Main.cpp isn't going to see it.

________________________________________

It's similar to the same reason why the following won't compile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>

template <class T>
struct Foo {
    void boo()
    {
       std::cout << "Non-specialized\n";
    }
};

int main()
{
    Foo<char> cfoo;
    Foo<int> ifoo;
    
    cfoo.boo();
    ifoo.boo();
}

template <>
struct Foo<int>
{
    void boo()
    {
       std::cout << "Specialized\n";
    }
};


I don't even think you can 'prototype' a template specialization; you'll just get a multiple definition error.
Last edited on
Thank you Ganado for responding . I realized that cpool has no such class ConnectionPoolFactory.. and have since backed off that namespace .. and based on your feedback.. I backed off trying to get this into a .cpp and .h file and just use the classes for now within my Main.cpp ... now getting a different error

Main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

class TMAConnection final : public cpool::Connection {
public:
    bool heart_beat() override { return connected; }

    bool is_healthy() override { return connected; }

    bool connect() override {
        connected = true;
        return connected;
    }

    void disconnect() override { connected = false; }

private:
    TMAConnection() = default;
    friend ConnectionPoolFactory<TMAConnection>;

    bool connected = false;
};

template <class TMAConnection>
class ConnectionPoolFactory<TMAConnection> {
public:
    static std::unique_ptr<cpool::ConnectionPool> create( const std::uint16_t num_connections ) {
        std::vector< std::unique_ptr<cpool::Connection> > connections;
        for ( std::uint16_t k = 0; k < num_connections; ++k ) {
            // cannot use std::make_unique, because constructor is hidden
            connections.emplace_back( std::unique_ptr<TMAConnection>( new TMAConnection{} ) );
        }
        return std::unique_ptr<cpool::ConnectionPool>( new cpool::ConnectionPool{std::move( connections )} );
    }
};

class ServerHandler : public myserverIf {
 public:
    ServerHandler(int num_of_connections) {

    auto tma_conn_pool = ConnectionPoolFactory<TMAConnection>::create(4);
  }
....

...


which yields

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-- Conan: Compiler GCC>=5, checking major version 9
-- Conan: Checking correct version: 9
-- Configuring done
-- Generating done
-- Build files have been written to: //build_cmake
Scanning dependencies of target server_server
[ 16%] Building CXX object CMakeFiles/server_server.dir/src/server_server.cpp.o
//src/server_server.cpp:41:12: error: ‘ConnectionPoolFactory’ does not name a type
   41 |     friend ConnectionPoolFactory<TMAConnection>;
      |            ^~~~~~~~~~~~~~~~~~~~~
//src/server_server.cpp:47:7: error: ‘ConnectionPoolFactory’ is not a class template
   47 | class ConnectionPoolFactory<TMAConnection> {
      |       ^~~~~~~~~~~~~~~~~~~~~
//src/server_server.cpp: In instantiation of ‘static std::unique_ptr<cpool::ConnectionPool> ConnectionPoolFactory<TMAConnection>::create(uint16_t) [with TMAConnection = TMAConnection; uint16_t = short unsigned int]’:
//src/server_server.cpp:65:64:   required from here
//src/server_server.cpp:53:71: error: ‘constexpr TMAConnection::TMAConnection()’ is private within this context
   53 |             connections.emplace_back( std::unique_ptr<TMAConnection>( new TMAConnection{} ) );
      |                                                                       ^~~~~~~~~~~~~~~~~~~
//src/server_server.cpp:40:5: note: declared private here
   40 |     TMAConnection() = default;
      |     ^~~~~~~~~~~~~
//src/server_server.cpp:55:56: error: ‘cpool::ConnectionPool::ConnectionPool(std::vector<std::unique_ptr<cpool::Connection> >&&)’ is protected within this context
   55 |         return std::unique_ptr<cpool::ConnectionPool>( new cpool::ConnectionPool{std::move( connections )} );
      |                                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from //src/server_server.cpp:9:
/home/ubuntu/.conan/data/connpool/1.0.0/bonk/prod/package/abd3ca9581f5ec3d6672fa2ee8818b1f09dbb082/include/connection-pool/pool.h:57:14: note: declared protected here
   57 |     explicit ConnectionPool( std::vector< std::unique_ptr< Connection > >&& connections );
      |              ^~~~~~~~~~~~~~
make[2]: *** [CMakeFiles/server_server.dir/build.make:63: CMakeFiles/server_server.dir/src/server_server.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/server_server.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
chmod: cannot access 'server_server': No such file or directory

this finally compiled, thanks for the heads up !

I wish I knew how to get these classes into their own .cpp and .h but when I try it just keeps complaining so.. will stick it all in main.cpp for now

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <connection-pool/pool.h>


class TMAConnection final : public cpool::Connection {
public:
    bool heart_beat() override { return connected; }

    bool is_healthy() override { return connected; }

    bool connect() override {
        connected = true;
        return connected;
    }

    void disconnect() override { connected = false; }

private:
    TMAConnection() = default;
    friend cpool::ConnectionPoolFactory<TMAConnection>;

    bool connected = false;
};

template <>
class cpool::ConnectionPoolFactory<TMAConnection> {

public:
    static std::unique_ptr<cpool::ConnectionPool> create( const std::uint16_t num_connections ) {
        std::vector< std::unique_ptr<cpool::Connection> > connections;
        for ( std::uint16_t k = 0; k < num_connections; ++k ) {
            // cannot use std::make_unique, because constructor is hidden
            connections.emplace_back( std::unique_ptr<TMAConnection>( new TMAConnection{} ) );
        }
        return std::unique_ptr<cpool::ConnectionPool>( new cpool::ConnectionPool{std::move( connections )} );
    }

};


class myserversHandler : public myserversIf {
 public:
  myserversHandler(int num_connections) {

    auto tma_conn_pool = cpool::ConnectionPoolFactory<TMAConnection>::create(4);
  }
Just saw this. Glad you have a workaround.
I wish I knew how to get these classes into their own .cpp and .h
You can put the template/template specializations into their own header, but you can't separate out template code into a .cpp file. You can separate out your TMAConnection class since it's not a class template. But you can't separate out your ConnectionPoolFactory.

Remember: #including a header is just a crude copy-paste mechanism that the pre-processor does. Nothing more.
Last edited on
Topic archived. No new replies allowed.