views:

389

answers:

4

Given:

template<typename T> class A {  
  B b;
  std::vector<T> vec1;
  std::vector<T> vec2;
}

I'd like B to have a member function that fill() that takes a reference to those to vectors and fills vec2 with values of T depending on some information contained in b.
One way of doing this is overloading fill() for each possible argument T:

fill(const std::vector<float>& a, std::vector<float>& b)

and so on but this will mean a lot of unnecessary duplication as the operations are the same for every possible T. Inside of fill() I could use vector::value_type for the calculations but I don't know how to declare it in such a way that it takes every kind of std::vector. The obvious way would be to use a free function with templates. Is there a simpler way of doing this?

+4  A: 

Templatize B.

template<typename T> class B {
  void fill(const std::vector<T>& a, std::vector<T>& b) { }
};

template<typename T> class A {  
  B<T> b;
  std::vector<T> vec1;
  std::vector<T> vec2;
}

If you don't want to templatize B, then templatize the fill function:

class B {
  template<typename T>
  void fill(const std::vector<T>& a, std::vector<T>& b) {}
};
Ben Collins
More info: B is part of a inheritance hierachy with pure virtual functions and wrapped in a smart pointer to the base class.Users would be required to instantiate B with the same type as A (which adds a possibility of error) and wouldn't be obvious to the users of the classes so I'd rather avoid that.
pmr
I realize refactoring large hierarchies is a pain, but you might also try to use a policy class as a template parameter instead of passing in smart pointers and apparently (based on your description) sacrificing type-safety for flexibility.
Ben Collins
+3  A: 

Templatize fill:

class B {
public:
  template<typename T>
  void fill(const std::vector<T>& a, std::vector<T>& b)
  { /*...*/ }
  //...
};

(From your description it sees that b should be a const std::vector<T>&.)

sbi
+2  A: 

You can define B as template class, fill as template function (inside a non-template class B) or, my favorite, use the standard std::transform/std::copy/std::fill, which are already template function, to populate your vector.
(All located inside <algorithm> header).

Oren S
Didn't know about template member functions in non-template classes. Best option so far with std::transform.
pmr
+2  A: 

You've gotten a number of answers, but I have to disagree with them, to at least some degree. My immediate reaction is that you shouldn't pass a vector to b::fill at all. Rather, you should pass an iterator (or maybe a pair of iterators). The rest is mostly right though: that still means fill should be a template member function. When you call it, you'll probably want to pass a std::back_insert_iterator, usually obtained with std::back_inserter.

Part of what you've said seems self-contradictory though: if b::fill modifies vec1 and vec2, they probably should not be passed as references to const. Admittedly, const doesn't have exactly its usual meaning when applied to a container, but the fact remains that passing a reference to const to a function whose sole intent is apparently to modify what's passed seems wrong.

Jerry Coffin
Agree I agree with the sentiment that you should be passing iterator ranges rather than containers. He should also check out iterator type erasure. Thomas Becker has an any_iterator class as does the Adobe Public Library.
David Joyner
About the references to const: Only the second vector will be modified.About using iterators: The fill operation will be rather heavy (a lot of insertions) and it can benefit from vector::reserve(int). How can I get that kind of performance improvement with an std::back_inserter?
pmr
reserve reserves _space_ (and also one of the constructor). it does not create object. you can use reserve() and than back_insert to it. The result it constructing (or assigning to) a pre-allocated space, which is just what you want. (and, for objects with heavy construction and light assignment, you may create the vector with the required size and not use back_inserter)
Oren S
Unfortunately, no -- there's no reason insert_iterators couldn't pass a `reserve` through to the underlying container, but it's not defined in the current interface.
Jerry Coffin