使用模板来克服缺乏基类的问题

Use template to overcome the lack of a base class?

本文关键字:基类 问题 克服      更新时间:2023-10-16

显然,标准容器既没有公共的基类,也没有公共的接口,尽管方法名是同质的。

问题:我必须用唯一类型的对象集合填充容器。容器可以是std::liststd::vectorstd::deque,也可能是其他一些自定义容器。下面的代码是最佳解决方案吗?

# include <string>
# include <iostream>
# include <list>
# include <vector>
# include <deque>
/*
 * Fill a container with two strings. The container
 * must expose the `clear` and `push_back` methods.
 */
template<typename T>
void f(T & t)
{
    t.clear() ;
    t.push_back("Alice") ;
    t.push_back("Bob") ;
}
int main(int, char*[])
{
    std::list<std::string>    l ;
    std::vector<std::string>  v ;
    std::deque<std::string>   q ;
    f(l) ;   // fill the list
    f(v) ;   // fill the vector
    f(q) ;   // fill the double-ended queue
    // possibly anything with `clear` and `push_back` methods
    // can be filled with `f`
    return 0 ;
}

谢谢你的建议!


编辑

这是我在第一篇文章中用f说明的情况:

struct AudioFormat
{
    uint32_t   samplerate ;   // Sampling frequency
    uint8_t    channels ;     // The number of channels
    uint8_t    bitdepth ;     // The number of bits per sample
} ;
class AudioDevice
{
    // many stuff skipped
    public :
      /*
       * Fills the container with available audio formats handled properly by the device
       */
      void GetSupportedAudioFormats(std::list<AudioFormat> &) ;
    // many stuff skipped
} ;

我正在寻找一种更好的方法来声明GetSupportedFormats,这样它就可以处理许多其他容器,而不仅仅是std::list s。

我的最爱是:

/*
 * Fill a container with two strings. The container
 * must expose the `clear` and `push_back` methods.
 */
template<typename T>
void f(T & t)
{
    t.clear() ;
    std::insert_iterator<T> it(t, t.end());
    *it++ = "Alice";
    *it++ = "Bob";
}

现在的约束是:clearinsert,所以它也可以与std::set一起工作。此外,它可以与任何类型的工作,你只需要专门为它的std::insert_iterator模板。

这是一个解决方案。

一个更"STL"风格的解决方案是使用std::back_inserter

char const* names[2] = { "Alice", "Bob" };
std::list<std::string> l;
std::vector<std::string> v;
std::deque<std::string> q;  
std::copy(names, names+2, std::back_inserter(l));
std::copy(names, names+2, std::back_inserter(v));
std::copy(names, names+2, std::back_inserter(q));

使用clear()和add()方法提供您自己的抽象类

class ContainerIterface
{
public:
  virtual void clear() = 0;
  virtual void add(const UniqueType &e) = 0;
};

然后你可以推导出像

这样的东西
template <typename Container>
class TemplatedContainer : public ContainerIntarface {
  virtual void clear() {c_.clear();}
  virtual void add(const UniqueType &e) {std::inserter(c_, c_.end()) = e;}
private:
  Container c_;
};

这假定在容器中只有一种类型要存储。如果不是这样,基类也会变成模板,派生类需要模板参数是模板(std::vector而不是std::vector<UniqueType>)