Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructing class from variadic templates

I'm trying to create a class called Sink which will create a pointer to the class you pass in, this is to wrap an api in RAII.

In the full version of this code, the custom class also inherits from another class, and there is static assets to check this. The pointer is also passed to the api.

But to keep it simple I've removed this.

This is the error I get from cpp.sh

 In function 'int main()':
43:30: error: no matching function for call to 'Sink<OneArg>::Sink(int)'
43:30: note: candidate is:
10:5: note: Sink<CustomSink, Args>::Sink(Args&& ...) [with CustomSink = OneArg; Args = {}]
10:5: note:   candidate expects 0 arguments, 1 provided

Code:

#include <string>
#include <iostream>
#include <memory>
#include <utility>

template<typename CustomSink, typename... Args>
class Sink
{
public:
    Sink(Args&&... args)
    {        
       _ptr = std::make_unique<CustomSink>(std::forward<Args>(args)...);        
    }
    ~Sink() 
    {
    }
private:
    std::unique_ptr<CustomSink> _ptr;
};


//////////////////////////////////////////////////////////////////////
class NoArg
{
public:
    NoArg() {};
    ~NoArg() {};
};

class OneArg
{
public:
    OneArg(int a) {
        std::cout << a << '\n';
    };
    ~OneArg() {};
};
//////////////////////////////////////////////////////////////////////


int main(){
    Sink<NoArg> noArgSink;   
    Sink<OneArg> oneArgSink(5);  

    return 0;
}
like image 443
Thomas Monkman Avatar asked Dec 08 '22 18:12

Thomas Monkman


2 Answers

Your issue here is with the placement of the template type Args. Right now you have Args in the class tempalte so

Sink<OneArg> oneArgSink(5);

Says Args is empty so Sinks constructor expects no arguments. What you need to do is move Args to the constructor by making it a template. That gives you

template<typename... Args>
Sink(Args&&... args)
{        
   _ptr = std::make_unique<CustomSink>(std::forward<Args>(args)...);        
}

And now the constructor will deduce the arguments passed to it instead of having to specify it when you declare the class.

like image 68
NathanOliver Avatar answered Dec 11 '22 09:12

NathanOliver


The template arguments of the constructor should be moved from the class to the templated constructor:

template<typename CustomSink>
class Sink
{
public:
    template <typename... Args>
    Sink(Args&&... args)
    {        
       _ptr = std::make_unique<CustomSink>(std::forward<Args>(args)...);        
    }
private:
    std::unique_ptr<CustomSink> _ptr;
};
like image 22
Jarod42 Avatar answered Dec 11 '22 09:12

Jarod42