Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use template to overcome the lack of a base class?

Tags:

c++

std

templates

Obviously, standard containers don't have a common base class, nor a common interface, although the method names are homogeneous.

The problem : I have to fill a container with a collection of objects of a unique type. The container can be a std::list, a std::vector or a std::deque, and possibly some other custom container. Is the following code the best solution ?

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

Thanks for any advice !


EDIT

Here is the case that I illustrated with f in my first post :

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

I am looking for a better way to declare GetSupportedFormats so it can handle many other containers, not only std::lists. That's the point of my first post.

like image 225
overcoder Avatar asked Aug 12 '11 17:08

overcoder


2 Answers

My favorite would be:

/*
 * 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";
}

The constraints are now: clear and insert, so it will also work with std::set for example. Also, it could work with any type, you would just have to specialise the std::insert_iterator template for it.

like image 51
PierreBdR Avatar answered Sep 17 '22 21:09

PierreBdR


That's one solution.

A more "STL" style solution is to use a 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));
like image 22
Peter Alexander Avatar answered Sep 18 '22 21:09

Peter Alexander