我很感激(在我的关卡中)一些相当复杂的模板问题的帮助。
让我解释一下我的系统'第一
建模基本的音频混合和流媒体系统,它有三个构建组件:
缓冲区,播放器将从中处理数据。
由于它们通过数据直接连接,因此它们的数据需要具有相同的类型。因此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>
,这可行,但编译时模板是我猜的更难的。
非常感谢任何帮助!
答案 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);
}
};
答案 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);
}
};