views:

90

answers:

2

I have an arbitrary STL container C, which contains elements of an arbitrary type T. I want to create an std::vector that has a copy of all the elements. What is the cleanest way to do this?

template <typename C>
void myfunction(C container){

     /*Derive the type T of elements within the container*/

     std::vector<T> mystack;

    /* Iterate over container and push_back() the elements into mystack*/
} 
+8  A: 

STL structures like vector and set should contain the value_type type that is typedef-ed to T.

std::vector<typename C::value_type> mystack;

BTW, you don't need to iterate over the container yourself. Just use

template <typename C>
void myfunction(const C& container){
  std::vector<typename C::value_type> mystack(container.begin(), container.end());
  ...
}
KennyTM
+8  A: 

For containers, Kenny has given the correct solution. However, many functions in C++ take pairs of iterators instead of containers … the same logic can be applied here. Iterators use iterator_traits to provide information about their related types:

template <typename It>
void myfunction(It start, It end) {
    // Get value for iterator:

    typedef typename std::iterator_traits<It>::value_type T;

    // Do something, e.g. calculate the minimum:

    T min_value = *std::min_element(start, end);
}

By the way, typename is necessary in the typedef because value_type is a so-called dependent type, i.e. it depends on the nature of a template argument and the C++ compiler cannot figure out on its own that it refers to a type name (rather than, say, a static method or variable) in this context.

Konrad Rudolph
That's a nice addition to Kenny's answer, although I'd feel much better about my up-vote if you wouldn't name an iterator pointing _one passed the last valid element_ the same as a common container member function retrieving the last valid element. That's way to much potential for confusion.
sbi
@sbi: **D’oh!** I’ve used this notation in my own code consistently *for years* and never noticed that it conflicts so badly with STL usage. Bad bad bad bad. :-(
Konrad Rudolph
I use `first`, `last`, like STL algorithms do. You have to cope with the fact that "last" is the last iterator *of* the range, not the iterator that points at the last element *in* the range.
Steve Jessop
@Konrad: I applaud to your reaction to a criticism of your code.
sbi
@Steve: `last` isn't ideal either, but at least it isn't overloaded with a subtly, but importantly different other meaning.
sbi
@sbi, How about `start` and `stop` then?
utnapistim
@utnapistim: I dunno. What's wrong with `begin` and `end`? Everybody immediately knows that `begin` points at the first element and `end` one behind the last, that `begin==end` means an empty range, and all that other cultural baggage coming with the STL and known by everyone who got their feet wet in it. No need to explain anything, no room for confusion, no ambiguities, everybody interprets the code the same way - and it's the way it was written. In programming, that's hard to beat.
sbi
@sbi: What’s wrong with `begin` and `end` is that we use a library that uses *only* free functions instead of methods (for reasons of extensibility). So there are free functions called `begin` and `end`. If you call your arguments the same, you can no longer call the functions (unless, of course, you qualify their namespace …). :-(
Konrad Rudolph
@Konrad: [Namespaces, exactly](http://stackoverflow.com/questions/2879555/2880136#2880136)! `:)` (Those free `begin()` and `end()` functions are in my toolbox, too.)
sbi