关于c ++:模板和继承,如何调用基本虚方法

Templates and inheritance, how to call base virtual method

我的C++框架有一个类层次结构。还有一个通用集合类用于处理对象集(如打印它们)。这是我简化的课堂设计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<iostream>
#include<vector>
using namespace std;
class Base {
public:
    virtual void print() const {cout <<"B" << endl;}
};
class Derived : public Base {
    int x;
public:
    Derived(int _x) : x(_x) {}
    virtual void print() const {cout <<"D" << x << endl;}
};

inline void print_elem(const int e) { cout << e << endl; }
inline void print_elem(const Base& e) { e.print(); }

template<class T>
class Collection {
private:
    vector<T> elems;
public:
    void add(const T& v) { elems.push_back(v); }
    void print() {
        for (unsigned i=0; i < elems.size(); ++i)
            print_elem(elems[i]);
    }
};

int main(int argc, const char *argv[]) {
    Collection<int> c1;
    c1.add(2); c1.add(5);
    c1.print();

    Collection<Derived> c2;
    c2.add(Derived(2)); c2.add(Derived(5));
    c2.print();
}

以上代码编译正常。问题是关于print_elem,因为我必须为每个支持的类型实现。我希望实现它的方式如下:

1
2
3
inline void print_elem(const Base& e) { e.print(); }
template<class T>
inline void print_elem(const T& e) { cout << e << endl; }

为基类和所有派生类以及所有其他类型指定实现时,应使用<<运算符,但存在编译错误,说明:

template argument deduction/substitution failed:
cannot convert ‘e’ (type ‘const Derived’) to type ‘const unsigned >
char*’
inline void print_elem(const T& e) { cout << e << endl; }

编译器是否可能将print_elem(const Base& e)与通用模板一起使用?


斯芬娜去营救!

如果参数继承自Base,则可以使用类型特征来阻止选择模板打印:

1
2
3
4
inline void print_elem(const Base& e) { e.print(); }

template<class T, class = std::enable_if_t<!std::is_base_of_v<Base, T> > >
inline void print_elem(const T& e) { cout << e << endl; }

你可以在这里看到一个活生生的例子


我用C++来解决C++ 11,灵感来自于@ AMC176的答案。感兴趣的代码片段将是:

1
2
3
4
inline void print_elem(const Base& e) { e.print(); }

template<class T, class enable_if<!is_base_of<Base,T>::value,Base>::type* = nullptr>
inline void print_elem(const T& e) { cout << e << endl; }