【问题标题】:Using variadic templates with templated class arguments使用带有模板化类参数的可变参数模板
【发布时间】:2016-07-04 21:34:03
【问题描述】:
#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。

【问题讨论】:

  • 未使用的模板“编译良好”大多没有意义。虽然存在一些逻辑,但真正的测试是在您实例化它时。
  • 另外,如果您使用的是 GCC,我建议您停止。 Clang 通常会提供明显更好的错误消息。
  • @xaxxon 我主要在 ARM Cortex 裸机上使用 GCC,但我认为 Clang 可能适用于该平台......

标签: c++ templates vector


【解决方案1】:

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

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

【讨论】:

  • 感谢您指出未定义 _buf 的问题,该问题的大小必须适合放置在待办事项列表中的模板类的大小。
【解决方案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);
}

【讨论】:

    【解决方案3】:

    您有一个没有基本情况的递归调用。最终你调用了make_classes&lt;&gt;(vec);,因为当你用一种类型调用它时,First 吃掉了它,Rest... 留空了。

    你需要一些东西来处理基本情况template&lt;class First&gt;,你应该很好。

    【讨论】:

      猜你喜欢
      • 2014-09-08
      • 2021-10-01
      • 1970-01-01
      • 2012-01-20
      • 2012-12-07
      • 2019-11-22
      • 2014-02-03
      • 2016-12-01
      • 1970-01-01
      相关资源
      最近更新 更多