C ++模板问题

时间:2016-10-05 14:13:56

标签: c++ templates generics inheritance interface

我很感激(在我的关卡中)一些相当复杂的模板问题的帮助。

让我解释一下我的系统'第一

建模基本的音频混合和流媒体系统,它有三个构建组件:

缓冲区播放器将从中处理数据。 由于它们通过数据直接连接,因此它们的数据需要具有相同的类型。因此Buffer<T> ~ Player<T>,模板必须匹配。

这些包含在经理中,最终将所有传入缓冲区管理到一个播放器中。

现在,Buffers和Players都需要一些不同的实现,因此它们由通用的接口表示为iPlayer和iBuffer。

我的目标是能够宣布这样的经理:

simple_manager<simple_player<float>>;

或至少失败

simple_manager<simple_player , float>;

由于我不确定第一个是否有解决方案,因此我在第二个方面的尝试是:

template <typename K>
class iManager {
    private:
        K player;
};

template <template <typename> class C , typename T>
class simple_manager : iManager< C<T> > {
    public:
        void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){
            player.play(_buffer,ad,condition);
        }


};

正如您所看到的,在具体类中,T标记要操作的数据类型,而C是我希望使用的具体类型的玩家。 界面只有一个模板,它再次标记具体的玩家类。所以K ~ C<T>

这不会编译(仅)以下错误:

simple_manager.cpp: In member function ‘void simple_manager<C, T>::play(iBuffer<T>&, audio_descriptor, bool*)’:
simple_manager.cpp:18:12: error: ‘player’ was not declared in this scope
            player.play(_buffer,ad,condition);
            ^~~~~~

我不知道是什么原因引起的。编译器是否可以推断出T必须从iPlayer继承,因为iPlayer必须实现play()方法。

如果我像这样定义simple_manager,我可以让它真正起作用:

class simple_manager : iManager< simple_player<float> > {...}

但仍然赢得了

class simple_manager : iManager< simple_player<T> > {...}

我很难过。如果我有来自Java的<T extends iPlayer>,这可行,但编译时模板是我猜的更难的。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

第一个问题是,player无法从派生类中访问,因为它标记为private而不是protected。你可以使它protected或添加一些protected成员函数来访问它:

template <typename K>
class iManager {
protected:
    K player;
};

然而,这仍然无法正常工作,因为iManager<C<T>>是一个依赖的基类,因此其成员对于非限定名称查找是隐藏的。要解决此问题,您可以通过this指针访问它:

void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){
    this->player.play(_buffer,ad,condition);
}

为了在第一个例子中得到很好的用法,你可以编写一个特征来从给定的类型中提取模板参数:

template <typename T> struct extract_inner;

template <template <typename> class C, typename T> 
struct extract_inner<C<T>> { using type = T; };

template <typename T> 
using extract_inner_t = typename extract_inner<T>::type;

然后,这可用于向iBuffer提供正确的参数:

template <typename T>
class simple_manager : iManager< T > {
public:
    void play(iBuffer<extract_inner_t<T>> & _buffer,
              const audio_descriptor ad, bool * condition){
        this->player.play(_buffer,ad,condition);
    }
};

Live demo

答案 1 :(得分:1)

你的问题非常简单。

你几乎掌握了所有语法,但你错过了一件事:this关键字。 当您扩展依赖于模板参数的类时,this将成为一个依赖名称。由于基类是依赖于子项上的模板参数的模板,因此编译器必须知道哪个名称来自基础,哪个名称不是。如果编译器不会请求消除歧义,可以专门化您的基类,在名称上抛出一堆并让您的子类使用它们。

要消除歧义,只需在来自基类的名称前添加this->关键字:

template <template <typename> class C , typename T>
struct simple_manager : iManager< C<T> > {
    void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){
            this->player.play(_buffer,ad,condition);
    }
};