【问题标题】:C++ Template troubleC++ 模板问题
【发布时间】:2017-02-14 00:57:39
【问题描述】:

我希望能在一个相当复杂的模板问题(对我的关卡而言)提供一些帮助。

让我先解释一下我的“系统”。

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

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

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

现在,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&lt;T&gt;

编译时(仅)出现以下错误:

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 的 &lt;T extends iPlayer&gt;,这会起作用,但我想编译时模板是一个更难的问题。

任何帮助将不胜感激!

【问题讨论】:

  • 我投票决定重新打开,因为除了名称查找之外还有更多问题,我认为 OP 也希望为他的第一个示例提供解决方案。如果您不同意,请随时投票关闭。

标签: c++ templates generics inheritance interface


【解决方案1】:

你的问题很简单。

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

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

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

【讨论】:

    【解决方案2】:

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

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

    但是,这仍然行不通,因为iManager&lt;C&lt;T&gt;&gt; 是一个依赖基类,因此它的成员对非限定名称查找是隐藏的。要解决这个问题,您可以通过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

    【讨论】:

    • 感谢您的快速答复。我是如此纠结于一个时间模板悖论,我什至从未考虑过这一点。也永远不会想到更优雅的解决方案,这对我来说似乎很神奇。或者我还有很多东西要学。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多