使用带有模板化类参数的可变参数模板

时间:2016-07-04 21:34:04

标签: c++ templates vector

#include <stdlib.h>
#include <stdint.h>
#include <vector>

struct MyClass1 {
        virtual ~MyClass1() = default;  
};

template <typename T>    
struct MyClass2 : public MyClass1 {};

template <class...C> class MyClass3 { //will be singleton class
    public:
        MyClass3() 
        {
            make_classes<C...>(_class_vec);
        }

    private:
       static const size_t _num_classes = sizeof...(C);
       static uint8_t *_buf[_num_classes];
       std::vector<MyClass1*> _class_vec;

       void make_classes(std::vector<MyClass1*> &vec) {}

       template <class First, class... Rest> void make_classes(std::vector<MyClass1*> &vec) {
            static size_t count;

            First* tmp = new (_buf[count++]) First;
            vec.push_back(tmp);
            make_classes<Rest...>(vec); 
        }   

};

int main() {
    auto foo = MyClass3<MyClass2<int>, MyClass2<char>>();
    return 0;
}

我试图将一组可变参数模板参数传递给Class3的构造函数,并使用placement new将它们放在适当大小的池的单元格中,其第一维在编译时计算。然后使用基础对象的类型构造一个指向它们的指针向量(传递给Class3模板的派生对象使用单个变量类型进行模板化。)

这编译好了,但是当我在main中创建一个Class3类型的对象时,我得到以下错误:

prog.cpp: In instantiation of 'void MyClass3<C>::make_classes(std::vector<MyClass1*>&) [with First = MyClass2<char>; Rest = {}; C = {MyClass2<int>, MyClass2<char>}]':
prog.cpp:32:29:   required from 'void MyClass3<C>::make_classes(std::vector<MyClass1*>&) [with First = MyClass2<int>; Rest = {MyClass2<char>}; C = {MyClass2<int>, MyClass2<char>}]'
prog.cpp:17:29:   required from 'MyClass3<C>::MyClass3() [with C = {MyClass2<int>, MyClass2<char>}]'
prog.cpp:38:57:   required from here
prog.cpp:32:29: error: no matching function for call to 'MyClass3<MyClass2<int>, MyClass2<char> >::make_classes(std::vector<MyClass1*>&)'
        make_classes<Rest...>(vec); 
                             ^
prog.cpp:27:55: note: candidate: template<class First, class ... Rest> void MyClass3<C>::make_classes(std::vector<MyClass1*>&) [with First = First; Rest = {Rest ...}; C = {MyClass2<int>, MyClass2<char>}]
            template <class First, class... Rest> void make_classes(std::vector<MyClass1*> &vec) {
                                                       ^
prog.cpp:27:55: note:   template argument deduction/substitution failed:
prog.cpp:32:29: note:   couldn't deduce template parameter 'First'
        make_classes<Rest...>(vec); 

使用可变参数模板实现此目的的正确方法是什么?请记住,我在嵌入式平台上工作,所以我的编译器兼容C ++ 11,但很多STL和Boost对我来说都不可用。

3 个答案:

答案 0 :(得分:2)

编译错误是因为对make_classes的最后一次递归调用是:

make_classes<>(vec);

当然,这与模板功能不匹配。

void make_classes(std::vector<MyClass1*> &vec) {}

这不是模板功能。之间有区别:

make_classes(vec);

make_classes<>(vec);

你可以尝试专门化模板功能,但是在整个模板类中,这会很快变得丑陋。

最简单的解决方案是将make_classes()替换为:

template <class First> void make_1class(std::vector<MyClass1*> &vec)
{
    static size_t count;

    First* tmp = new (_buf[count++]) First;
    vec.push_back(tmp);
}

template <typename OneClassLeft>
void make_classes(std::vector<MyClass1*> &vec)
{
    make_1class<OneClassLeft>(vec);
}

template <class First, class Second, class ...Rest>
void make_classes(std::vector<MyClass1*> &vec)
{
    make_1class<First>(vec);

    make_classes<Second, Rest...>(vec);
}

答案 1 :(得分:2)

代码中的递归缺少基本情况,即具有空参数包的情况 非模板成员函数不参与游戏,因为您始终使用以下行明确地专门化模板成员函数:

make_classes<Rest...>(0, vec);

可能的解决方案是:

  • 修改构造函数:

    MyClass3() 
    {
        make_classes<C...>(0, _class_vec);
    }
    
  • 更新make_classes个功能:

    template<typename... T>
    std::enable_if_t<sizeof...(T)==0>
    make_classes(int, std::vector<MyClass1*> &vec) {}
    
    template <class First, class... Rest> void make_classes(char, std::vector<MyClass1*> &vec) {
            static size_t count;
    
            First* tmp = new (_buf[count++]) First;
            vec.push_back(tmp);
            make_classes<Rest...>(0, vec); 
    }
    

注意:除非您在某处定义_buf,否则无论如何都不会编译。

答案 2 :(得分:1)

你有一个没有基本情况的递归调用。最后,您正在调用make_classes<>(vec);,因为当您使用一种类型调用它时,First吃掉了Rest...并且template<class First>为空。

你需要一些东西来处理这个基本案例Parameterized,你应该做得很好。