Search code examples
c++templatesconstructor

Constructor templates in a nontemplate class C++


I have a non-template class (Uart) and want to create template constructor. It needs to take another template class object (SafeQueue). Then this constructor will call another template function defined inside the class.

class signatures are given below;

class UartCommunication
{
public:
    UartCommunication(const char *port, speed_t baudRate);

    template <typename SendStruct, typename ReceiveStruct, typename SendQueue = SafeQueue<SendStruct>, typename ReceiveQueue = SafeQueue<ReceiveStruct>>
    UartCommunication(const char* port, speed_t baudRate, 
                                        SendQueue& sendQueue, ReceiveQueue& receiveQueue,
                                        int pollingTime, bool sendIfReceived)
    {
        port_ = port;
        baudRate_ = baudRate;

        serial_fd_ = open(port_, O_RDWR | O_NOCTTY | O_NDELAY);
        if (serial_fd_ == -1)
        {
            std::cerr << "Error opening serial port" << std::endl;
            // Handle error
        }
        std::cout << "serial_fd_:" << serial_fd_ << std::endl;
        ConfigureSerialPort();

        // Start a thread to receive data
        receiveThread_ = std::thread(&SendAndReceiveStruct<SendStruct, ReceiveStruct>, this, 
                                                sendQueue, receiveQueue, pollingTime, sendIfReceived);
    }
    // SentAndReceiveStruct from UART
    template <typename SendStruct, typename ReceiveStruct, typename SendQueue = SafeQueue<SendStruct>, typename ReceiveQueue = SafeQueue<ReceiveStruct>>
    void SendAndReceiveStruct(SendQueue& sendQueue, ReceiveQueue& receiveQueue, int pollingTime, bool sendIfReceived)
    {
     ///codes
    }
}

///

// A threadsafe-queue.
template <class T>
class SafeQueue
{
}

I can build the code without creating any object from Uart class using template const. Actually SendAndReceiveStruct function has the same signature with the const and can be called in a thread function. But when I try to create a Uart object with a similar way;

UartCommunication<InputStruct, OutputStruct> pcUart("/dev/ttyUSB0", B921600, AlgoTester::safeQueueInstanceAlgoInput, AlgoTester::safeQueueInstanceAlgoOutput, 20, false);

I get class "UartCommunication" may not have a template argument listC/C++(519) ‘UartCommunication’ is not a templateGCC error. I'm providing the template of the SafeQueue instance but is it ambiguous to use it like that? I need to use the safequeue tempalte as an object, so I cant directly use safequeue object as a template.

Thanks for the help.


Solution

  • Template constructors are meant to work with template argument deduction. Possible work-arounds:

    1. re-design constructor to accept some "strategy" object which allows template arguments to be deduced
    2. make a free-standing or static factory function if exposing copy\move functionality is acceptable
    3. create a separate template member function to initialize object's state.
    4. redesign class to be a template, possibly with a non-template base

    E.g. 2nd method:

    class UartCommunication
    {
     public:
        UartCommunication(UartCommunication&&) /*...*/
    
    
        template <typename SendStruct, typename ReceiveStruct, typename SendQueue = SafeQueue<SendStruct>, typename ReceiveQueue = SafeQueue<ReceiveStruct>>
        friend UartCommunication make_uart(const char*, speed_t, 
                                            SendQueue& , ReceiveQueue& ,
                                            int , bool );
    
    }
    
    // define make_uart
    
    int main()
    {
        UartCommunication uart = make_uart<InputStruct, OutputStruct> ( /*...*/);
    }