从可变参数模板构造类

时间:2017-05-05 13:31:03

标签: c++ templates variadic-templates

我正在尝试创建一个名为Sink的类,它将创建一个指向您传入的类的指针,这是在RAII中包装api。

在此代码的完整版本中,自定义类也继承自另一个类,并且有静态资产来检查它。指针也传递给api。

但为了保持简单,我已将其删除了。

这是我从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

代码:

#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;
}

4 个答案:

答案 0 :(得分:5)

构造函数的模板参数应该从类移动到模板化构造函数:

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;
};

答案 1 :(得分:5)

此处的问题在于模板类型Args的展示位置。现在你在课堂上有Args,所以

Sink<OneArg> oneArgSink(5);

表示Args为空,因此Sink的构造函数不需要参数。您需要做的是将Args移动到构造函数中,方法是将其作为模板。这给了你

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

现在构造函数将推导传递给它的参数,而不必在声明类时指定它。

答案 2 :(得分:3)

根据您的设计,您必须写:

Sink<OneArg, int> oneArgSink(5);

demo

实际上,构造函数的参数的数量和类型由模板的可变参数部分(typename ... Args)决定。但这部分是附加到类,而不是构造函数。因此,您必须在实例化模板时指定它。

否则,如果您想尊重实例化并让编译器确定模板参数,则必须将模板的可变元部分移动到构造函数(请参阅Jarod42 answerNathanOliver's one

答案 3 :(得分:1)

您声明类Sink的方式意味着您需要在模板实例化时指定Args...

这意味着如果你声明Sink<OneArg>,你实际上是使Args...为空,而构造函数并不期望任何参数。这就是编译器抱怨将参数传递给构造函数的原因。

您只需要构造函数中的可变参数模板。这样,您甚至可以容纳具有多个具有不同参数数量的构造函数的类。

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