【问题标题】:Templates and inheritance, how to call base virtual method模板和继承,如何调用基虚方法
【发布时间】:2018-04-18 12:30:42
【问题描述】:

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

#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,因为我必须为每种支持的类型实现。 我想像这样实现它:

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

为Base和所有派生类指定实现,所有其他类型应该&lt;&lt;操作符,但是有编译错误说:

模板参数推导/替换失败:
无法将“e”(类型“const Derived”)转换为类型“const unsigned > 字符*'
内联 void print_elem(const T& e) { cout

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

【问题讨论】:

  • 我认为 template&lt;class T&gt; 应该在您调用 e.print() 的函数之上,而不是在另一个调用 cout 的函数之上,这就是您收到错误的原因。
  • @PasserBy 我不认为他打算提供operator &lt;&lt; 它有一个print 功能我认为模板放错了位置。

标签: c++ templates inheritance


【解决方案1】:

受@amc176 答案的启发,我为 c++11 编写了解决方案。 感兴趣的代码片段是:

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

【讨论】:

    【解决方案2】:

    SFINAE 来救援!

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

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

    你可以看到一个活生生的例子here

    【讨论】:

    • 谢谢!可能与 -std=c++17 编译器标志一起使用。我正在使用-std=c++11。您的回答使我朝着正确的方向前进。所以我将其添加为答案。
    猜你喜欢
    • 1970-01-01
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 2016-07-12
    • 2011-06-07
    • 1970-01-01
    相关资源
    最近更新 更多