C2666 error with functions/c'tors taking variable parameters

J

John Shell

Hello, all.
The following code results in a C2666 error (2 overloads have similar
conversions).

class FSVec2D
{
public:
FSVec2D()
{ // code omitted
}
FSVec2D(double first, ...)
{
va_list args;
va_start(args, first);
double d = first;
for (int i = 0; i < 2; ++i)
{
_data = d;
d = va_arg(args, double);
}
va_end(args);
}
FSVec2D(const FSVec2D& _r, double _w)
{
_data[0] = _r[0];
_data[1] = _w;
}
double& operator[](int i)
{ return _data; }
const double& operator[](int i) const
{ return _data; }
private:
double _data[2];
};

FSVec2D v2(1.1, 2.2); // Error here

The two overloads that it sties are the default, compiler-generated
copy constructor and the constructor that takes a FSVec2D reference
and a double as parameters. Apparently, the intended constructor with
the variable parameters isn't even considered. This appears to me to
be a compiler bug. How can it convert a double to a class reference?
Am I making an erroneous assumption?

BTW, this code is a simplification of the original code. The
constructor above taking the reference and a double, of course,
doesn't make much sense. The original class is a parameterized class
as follows (notice the reference to a vector one size smaller). I
guess I could write an explicit specialization of the class for _Size
of 2 and eliminate the last constructor, since I have no use for a
vector of size 1. However, correct me if I'm wrong, I would have to
duplicate all of the rest of the functions in the class. Right?

template <size_t _Size, class _Type>
class FSVector
{
// Fixed-size vector
public:
FSVector();
FSVector(_Type first, ...);
FSVector(const FSVector<_Size - 1, _Type>& _r, _Type _w);
// ...
private:
_Type _data[_Size];
};

Other observations:
This error doesn't just happen with constructors. It also happens with
member functions and static member functions if one has the variable
parameter list and the other has the reference and primitive
parameters, as long as the reference is to a 'similar' class. By that
I mean, for the simplified sample (non-template) class above, it has
to be the same class. In the template class, the class reference isn't
to the exact same class, but uses the same template.

Interestingly, if I supply a copy-constructor (or in the case of
member functions), the compiler says there are 2 overloads that have
similar conversions, but only provides reference to the one with the
non-varible parameters. That is, it says "could be 'blah blah'" but
omits the "or 'blah blah blah'".

Thanks for any help or comments.

-John
 
D

Doug Harrison [MVP]

Hello, all.
The following code results in a C2666 error (2 overloads have similar
conversions).

class FSVec2D
{
public:
FSVec2D()
{ // code omitted
}
FSVec2D(double first, ...)
{
va_list args;
va_start(args, first);
double d = first;
for (int i = 0; i < 2; ++i)
{
_data = d;
d = va_arg(args, double);
}
va_end(args);
}
FSVec2D(const FSVec2D& _r, double _w)
{
_data[0] = _r[0];
_data[1] = _w;
}
double& operator[](int i)
{ return _data; }
const double& operator[](int i) const
{ return _data; }
private:
double _data[2];
};

FSVec2D v2(1.1, 2.2); // Error here

The two overloads that it sties are the default, compiler-generated
copy constructor and the constructor that takes a FSVec2D reference
and a double as parameters. Apparently, the intended constructor with
the variable parameters isn't even considered. This appears to me to
be a compiler bug. How can it convert a double to a class reference?

Am I making an erroneous assumption?


It's considering these ctors:

FSVec2D(double first, ...) // 1
FSVec2D(const FSVec2D& _r, double _w) // 2

Ctor (1) is an exact match on the first argument but an ellipsis match on
the second. Ctor (2) is an exact match on the second argument, but the
first one requires creation of a temporary FSVec2D via (1). Neither ctor is
considered better than the other for overload resolution, so the attempted
creation of v2 is ambiguous. To fix this, you can label (1) "explicit".
 
J

John Shell

Doug,

Thanks. That works. I thought I had tried that, but I guess I had put
the explicit on the other constructor.

However, I now have a problem with my template class when I try to
make explicit instantiations of it for exporting from a library. As
stated in my original post (modified by adding the 'explicit'), I have
the following class declaration:

template <size_t _Size, class _Type>
class FSVector
{
// Fixed-size vector
public:
FSVector();
explicit FSVector(_Type first, ...);
FSVector(const FSVector<_Size - 1, _Type>& _r, _Type _w);
// ...
};

I then have the following in the .h file for the DLL containing the
above class:

#ifdef TPILINEARMATH_EXPORTS
#define TPILINEARMATH_API __declspec(dllexport)
#else
#define TPILINEARMATH_API __declspec(dllimport)
#endif

#include "FSVector.h"

// Explicit instantiation of common FSVector classes.
template class TPILINEARMATH_API FSVector<2, float>;
template class TPILINEARMATH_API FSVector<2, double>;
template class TPILINEARMATH_API FSVector<3, float>;
template class TPILINEARMATH_API FSVector<3, double>;
template class TPILINEARMATH_API FSVector<4, float>;
template class TPILINEARMATH_API FSVector<4, double>;

I get the following warning for each of the explicit instantiations:
warning C4661: 'FSVector<_Size,_Type>::FSVector(const
FSVector<1,_Type> &,_Type)' : no suitable definition provided for
explicit template instantiation request

accompanied by a:
see declaration of 'FSVector<_Size,_Type>::__ctor'
referring to the 3rd c'tor.

However, if I have a static member function like this, instead of the
3rd c'tor:

static FSVector<_Size, _Type> construct(const FSVector<_Size - 1,
_Type>& _r, _Type _w);

the compiler doesn't have a problem with this. I don't understand why
it would have a problem with the constructor and not a static
function, but I guess I can use that instead. So, in an importing
application, I could have something like this:

FSVector<2, double> v2(1.1, 2.2);
FSVector<3, double> v3 = FSVector<3, double>::construct(v2, 3.3);

Unless you or someone else has a solution to the above problem, I'll
just use it that way.

Thanks again.

-John
 
J

John Shell

Never mind. This was my bad. (Had some code commented out. Doh!)

Thanks again.

-John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top