Quote Originally Posted by PredicateNormative
Ok, it's a bit convoluted but it works. If you think any of it is a bad idea, or could be done in a better way then let me know.

I defined a helper class:
Code:
template <typename IteratorCategory_, typename Buffer_>
class AssignmentHelper
{
public:
  template <typename Iter_>
  void assign(Iter_ first, Iter_ last, Buffer_& buffer)
  {
    buffer.assignUsingIteration(first, last);
  }
};
which I partially specialised as follows:

Code:
template <typename Buffer_>
class AssignmentHelper<std::random_access_iterator_tag, Buffer_>
{
public:
    template <typename Iter_>
    void assign(Iter_ first, Iter_ last, Buffer_& buffer)
    {
      buffer.assignUsingMemcpy(first, last);
    }
};
I then created a function to test the value_type of my BufferClass:

Code:
//A minor modification of how Andrei Alexandrescu achieves 
//primative data type recognition in his book "Modern C++ Design"
template<typename T>
bool isPrimitive(T)
{
    typedef char Small;
    typedef char (&Big)[2];
    Small Test(long double);
    Big Test(...);
    return sizeof( Test(T()) ) == sizeof(Small) ;
}
Finally, I redefined my BufferClass as follows:

Code:
template <typename T>
class BufferClass
{
public:
  typedef T value_type;

  template <typename Iter_>
  void assign(Iter_ first, Iter_ last)
  {
    AssignmentHelper<typename std::iterator_traits<Iter_>::iterator_category, BufferClass<T> > assignHelper;
    assignHelper.assign(first, last, *this);
  }

  template <typename Iter_>
  void assignUsingMemcpy(Iter_ first, Iter_ last)
  {
    if(!isPrimitive(value_type())) 
    {
      std::cout << "Buffer<T> value_type is non-POD: ";
      assignUsingIteration(first, last);
    }
    else
    {
      std::cout << "Can use memcpy" << std::endl;
    }
  }

  template <typename Iter_>
  void assignUsingIteration(Iter_ first, Iter_ last)
  {
    std::cout << "Can't use memcpy" << std::endl;
  }

  //...

private:
  //...
};
Now, when I run it with:

Code:
int main()
{
  std::vector<double> vec;
  std::list<double> lst;

  BufferClass<double> test;
  
  std::cout << "Test with std::list:\n  -> ";
  test.assign(lst.begin(),lst.end());

  std::cout << "Test with std::vector:\n  -> ";
  test.assign(vec.begin(),vec.end());

  std::vector< std::vector<double> > vecNonPod;
  BufferClass<std::vector<double> > nonPodTest;

  std::cout << "Test with std::vector with non-POD value_type:\n  -> ";
  nonPodTest.assign(vecNonPod.begin(),vecNonPod.end());

}
I get the following heart warming output:

Code:
Test with std::list:
  -> Can't use memcpy
Test with std::vector:
  -> Can use memcpy
Test with std::vector with non-POD value_type:
  -> Buffer<T> value_type is non-POD: Can't use memcpy
I would appreciate any feedback.
I do not think it is safe to assume that all random access iterators will iterate over contiguous memory, just that they provide constant-time access to any element in the collection. If a random access iterator operates on a single channel of an interlaced buffer, for instance, memcpy would not work correctly. I think your best bet would be the specialize for those iterators you know to be contiguous, such vector::iterator and string::iterator. This could even be wrapped up tidily in something like an is_contiguous type trait.