Hello,

I have a problem creating a template class with copy ctor and cast operator to class of base template (using gcc 4.2). The program compiles if only one of them is defined but is not compiling if both (copy ctor and cast operator) are defined.
The compiler error is
error: no matching function for call to 'Vector<float>::Vector(Vector<float>)'
note: candidates are: Vector<F>::Vector(Vector<F>&) [with F = float]
and is referring to the assignment:
Vector<float> pf = pd;

Here is simple example of the class:
vector.h:

template<class F> 
class Vector
{
public:
   Vector(F x1, F y1, F z1):x(x1),y(y1),z(z1)
   {
   }

   // This copy constructor is ok if cast operator is not defined
   Vector(Vector<F>& source)
   {
   }

   // This cast operator is ok if copy constructor is not defined
   template<class D> operator Vector<D> () const;

   F x,y,z;
};

vector.cpp

template <class F> template<class D>
Vector<F>::operator Vector<D> () const
{
   return Vector<D>(x,y,z);
}

main.cpp

void TestVector(Vector<double> v)
{
}

int main()
{
   Vector<double> pd(5.6,3.4,2.4);

   // use the cast operator works if copy ctor is not defined
   Vector<float> pf = pd;

   // use the copy ctor works if cast operator is not defined
   TestVector(pd);
}

Recommended Answers

All 8 Replies

Your main.cpp needs to have visibility of the definition of the conversion (or cast) operator. In other words, the implementation of the operator needs to be inlined into the vector.h: otherwise the compiler cannot instantiate the template.

Unrelated to your problem: it is usually a good idea for copy constructors to have their arguments const: copying an object usually does not change the original.

Thank you for looking into this.

I agree with const argument in copy constructor.
I've tested your idea with microsoft compiler (I'm at work now) and it worked.
I will test with gcc compiler at home to see if also works.

it seems to be a problem with the gcc compiler
using microsoft compiler the code works, using the gcc is not working

I can't compile your code with VC++ 9 because it's an example of ill-formed C++ program.
If you define (wrong) copy constructor with Vector<F>& argument, it's impossible to initialize Vector<float> variable with Vector<double> initializator.
The only possible way to do that is:
1. Convert Vector<double> object to temporary Vector<float> object.
2. Use Vector<float> copy constructor with const Vector<float>& parameter, because C++ forbid to bind non-const reference to temporary objects.

No such constructor: you define your own copy constructor with non-const reference.

If you discard user-defined copy constructor, default (compiler generated) copy constructor will be used, that's OK.
If you discard conversion operator, you can't compile the program again (no copy constructor Vector<float> with const Vector<double> argument).

Summary: always define copy constructors with const arguments

Vector(const Vector<F>& source)

(except special cases when you know what happens ;) )...

Hello Mr ArkM

The code posted in the article was created to prove the problem. I already agreed that copy constructor should have const parameter.
The problem is not related to converting from float to double. You can use if you like pd as vector<int> and pf as vector<double> and same problem will occur.
The problem is that if I have both the copy constructor and the cast operator there will be a compilation error in gcc 4.2 compiler and I want to know if there is an workaround for this, since I need to have both copy constructor and cast operator. Also as additional test with visual studio 2005 the code is compiled.

It seems you don't understand me: the code IS NOT compiled with VC++ 2008 and I'm trying to explain you why. No need in any "workarounds", correct semantics error in the CODE (not in the g++): declare copy constructor as usually with const Vector<F>& parameter.

void TestVector(Vector<double> v)
{
}

int main()
{
   Vector<double> pd(5.6,3.4,2.4);

   // use the cast operator works if copy ctor is not defined
   Vector<float> pf = pd;

   // use the copy ctor works if cast operator is not defined
   TestVector(pd);
}

In the above example, Vector<float> pf = pd won't work because the immediate assignment given a storage type before the identifier is the call to the constructor for the given type. Because it is a call to the constructor, the compiler will do a lookup for a constructor that accepts the given type. You might be successful if your class took more than just one type as a template parameter, and allow a call to the constructor such that your assignment would be legal.

For example, Vector<float, double> pf = pd In which the second template argument would be used as a means of resolving the other type.

You could either do this, or (possibly) throw pf on the stack without initializing it, then calling the operator () which is what you probably intended to do--

void TestVector(Vector<double> v)
{
}

int main()
{
   Vector<double> pd(5.6,3.4,2.4);

   Vector<float> pf; // throwing pf on the stack

   pf = pd<float>(); // calling overloaded operator () in pd

   TestVector(pd);
}

-- then again it's just a theory to help push you in the right direction.

Sorry, you were right. When I've tested with Visual Studio 2005 I've tested the code with const parameter in copy constructor but when I've tested with gcc I tested with not const parameter in copy constructor and that's why failed.

Thank you for help, I can mark this as fixed.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.