Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ basic constructor question

How should I handle the following situation :

I am writing my own 2D vector class and have the following code:

class Vector2 : public (...)
public:

   Vector2(float x, float y) {

      local_vector_storage_[0] = x;
      local_vector_storage_[1] = y;
   }

   template <typename Iterator> Vector2(Iterator begin, Iterator end) {

      ASSERT(end - begin == 2);

      resize(2);

      std::copy(begin, end, local_vector_storage_.begin());
   }

// ...
};

Now if I say Vector2 v(3.0f, 4.0f); it compiles fine and calls the appropriate float constructor.

But if I write Vector2 v(3, 4); it fails because the templated iterator constructor "fits better" and Vector2(Iterator(3), Iterator(4)) is called.

What should I do in this case?

My idea was about introducing assign(It1, It2) member method instead of the constructor but maybe there is a better solution?

Edit:

Also, what do you think about ASSERT(end - begin == 2) line? I know that this means I can't, for example, pass iterators of std::list, but brings additional safety. Should I do this or not?

like image 414
Yippie-Ki-Yay Avatar asked Jul 08 '10 15:07

Yippie-Ki-Yay


1 Answers

Something like this seems to work:

template<typename T>
struct notnumeric {typedef int OK;};

template<>
struct notnumeric<int> {};

class Vector2
{
public:
   Vector2(float x, float y)
   {
   }

   template <typename Iterator>
   Vector2(Iterator begin, Iterator end, typename notnumeric<Iterator>::OK dummy = 0)
   {
   }
};

I believe it's using SFINAE to prevent the compiler selecting the second ctor for non-numeric types.

As for ASSERT (end - begin == 2), I think you should be using std::distance(begin, end) to determine the distance between two iterators.

like image 102
jon-hanson Avatar answered Sep 29 '22 13:09

jon-hanson