使用模板来克服缺少基类?

时间:2011-08-12 17:09:46

标签: c++ templates std

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

问题:我必须使用一组唯一类型的对象填充容器。容器可以是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。这是我第一篇文章的重点。

3 个答案:

答案 0 :(得分:6)

我最喜欢的是:

/*
 * 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模板。

答案 1 :(得分:3)

这是一个解决方案。

更“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));

答案 2 :(得分:1)

使用方法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_;
};

这假设您只有一种类型存储在容器中。如果不是这样,你的基类也变成了一个temaplate,派生类需要一个模板参数作为模板(std::vector而不是std::vector<UniqueType>