0

I have 4 files: websocket.hpp

#include <memory>
#include <functional>

namespace boost {
namespace asio {
class io_context;
} // ns asio
} // ns boost

namespace izycoinscppapi {

namespace feedhandler {

struct websockets {
    websockets(const websockets &) = delete;
    websockets& operator= (const websockets &) = delete;
    websockets(websockets &&) noexcept = default;
    websockets& operator= (websockets &&) noexcept = default;

    using on_message_received_cb = std::function<void(const char *channel, const char *ptr, std::size_t size)>;

    websockets(
         boost::asio::io_context &ioctx
        ,std::string host
        ,std::string port
        ,on_message_received_cb cb = {}
    );
    ~websockets();

    using handle = void *;

    void unsubscribe(const handle &h);
    void async_unsubscribe(const handle &h);
    void unsubscribe_all();
    void async_unsubscribe_all();

    template<typename F>
    handle w_start_subscription(std::string target, std::string payload, F cb);
    
private:
    struct impl;
    std::unique_ptr<impl> pimpl;

};


} // ns feedhandler

} // ns izycoinscppapi

#endif

websocket.cpp

websockets::websockets(
     boost::asio::io_context &ioctx
    ,std::string host
    ,std::string port
    ,on_message_received_cb cb
)
    :pimpl{std::make_unique<impl>(ioctx, std::move(host), std::move(port), std::move(cb))}
{}

websockets::~websockets()
{}

template<typename F>
websockets::handle websockets::w_start_subscription(std::string target, std::string payload, F cb) {
    return pimpl->start_subscription(target, payload, std::move(cb));
}

wsapi.hpp

#ifndef __izycoinscppapi__exchanges__binance__wsapi_hpp
#define __izycoinscppapi__exchanges__binance__wsapi_hpp

#include <memory>
#include <functional>
#include <vector>

#include <izycoinscppapi/feedhandler/websocket.hpp>

namespace boost {
namespace asio {
class io_context;
} // ns asio
} // ns boost

namespace izycoinscppapi {

namespace feedhandler {
namespace ws {
struct fh_price_t;
} // ns ws

struct websockets;

} // ns feedhandler

namespace exchanges {

namespace binance {

namespace errors {
struct error_t;
}

namespace ws {

struct book_ticker_t;

struct wsapi {

    wsapi(
         boost::asio::io_context &ioctx
        ,std::string host
        ,std::string port
        ,feedhandler::websockets::on_message_received_cb cb = {}
    );
    ~wsapi();

    // https://github.com/binance/binance-spot-api-docs/blob/master/web-socket-streams.md#individual-symbol-book-ticker-streams
    using on_book_received_cb = std::function<bool(const char *fl, int ec, std::string errmsg, book_ticker_t receivedmsg, feedhandler::ws::fh_price_t returnmsg, binance::errors::error_t err)>;
    feedhandler::websockets::handle books(std::vector<std::string> pairs, on_book_received_cb cb);

    void async_unsubscribe(const feedhandler::websockets::handle &h);
    void async_unsubscribe_all();

private:
    std::unique_ptr<feedhandler::websockets> pwebsockets;
};

} // ns ws

} // ns binance

} // ns exchanges

} // ns izycoinscppapi
 
#endif // 

wsapi.cpp

feedhandler::websockets::handle wsapi::books(std::vector<std::string> pairs, on_book_received_cb cb) { 
    std::string target = build_target(pairs, "bookTicker");
    std::string payload{""};
    return pwebsockets->w_start_subscription<on_book_received_cb>(target, payload, std::move(cb));
}

As you can see, the w_start_subcription function exists in websocket.hpp and websocket.cpp, it is called in wsapi.cpp via the books function call Here is my main.cpp file

auto books_handler = wsapi.books (
        selected_pairs,
        [&timer1, &output_file] (const char *fl, int ec, std::string errmsg, auto received_msg, auto msg, auto err) {}
);

When I compile with CMake, I get this error

undefined reference to « void* izycoinscppapi::feedhandler::websockets::w_start_subscription<std::function<bool (char const*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, izycoinscppapi::exchanges::binance::ws::book_ticker_t, izycoinscppapi::feedhandler::ws::fh_price_t, izycoinscppapi::exchanges::binance::errors::error_t)>
>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<bool (char const*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, izycoinscppapi::exchanges::binance::ws::book_ticker_t, izycoinscppapi::feedhandler::ws::fh_price_t, izycoinscppapi::exchanges::binance::errors::error_t)>) ».

But the function exists.

I have no idea why I get this error message.

  • You need to define function templates in the header. https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – joergbrech Dec 04 '22 at 19:58

0 Answers0