PDA

View Full Version : template parameter and conversion operator



bitChanger
20th April 2006, 16:03
The following code will compile with MSVC 7.1 and with g++ 2.95.3
However, I need it to compile with g++ 3.4.4 which it does not.

If i'm reading my books correctly the template parameter has infinite possible types while operator conversions have a finite number of types, therefore this breaks the c++ standard. :o

Can someone help me find a workaround and/or a g++ flag to allow this to work.

Thanks.

g++ 3.x and up give the following error:

main.cpp: In function `void setType(const MyType&)':
main.cpp:21: error: 'const class MyType' has no member named 'operator ValType'




#include <string>
using namespace std;

class MyType
{
public:
MyType() {}
~MyType() {}

operator char() const { return 'a'; }
operator int() const { return 1; }
operator double() const { return 2.0; }
operator float() const { return 3.0f; }
};

template<typename ValType>
void setType(const MyType& val)
{
ValType type;
type = val.operator ValType();
}

int main()
{
MyType a;
setType<double>(a);
return 0;
}

jacek
20th April 2006, 18:51
You could try:
template< typename ValType >
void setType( const MyType& val )
{
ValType type;
type = static_cast< ValType >( val );
}
PS. I use g++ 3.3.6 and both versions compile fine.

bitChanger
20th April 2006, 18:58
I've tried to compile it with 3.4.4 and 4.1.0 and got the same error.

In my accual application I can't just do a static cast on val because the conversion operator actually converts a private void* of data into the appropriate type not the class itself.

jacek
20th April 2006, 19:30
In my accual application I can't just do a static cast on val because the conversion operator actually converts a private void* of data into the appropriate type not the class itself.
It does exactly the same thing:
#include <iostream>
#include <string>
using namespace std;

class MyType
{
public:
MyType() {}
~MyType() {}

operator char() const { cerr << "char" << endl; return 'a'; }
operator int() const { cerr << "int" << endl; return 1; }
operator double() const { cerr << "double" << endl; return 2.0; }
operator float() const { cerr << "float" << endl; return 3.0f; }
};

template<typename ValType>
void setType(const MyType& val)
{
ValType type;
type = static_cast< ValType> ( val );
}

int main()
{
MyType a;
setType<double>(a);
return 0;
}
Output:

$ ./a.out
double

You could implement it in a similar way as QVariant::value() was implemented.

bitChanger
20th April 2006, 21:24
Now I know why I was trying to explicitly call the conversion operator. In my application the type is complex. This gets ambiguous with the complex copy constructor.

Any thoughts on this one? ;)



#include <string>
#include <complex>
using namespace std;

class MyType
{
public:
MyType() {}
~MyType() {}

operator char() const { return 'a'; }
operator int() const { return 1; }
operator double() const { return 2.0; }
operator float() const { return 3.0f; }
operator complex<double>() const { return complex<double>(1.0,1.0); }
};

template<typename ValType>
void setType(const MyType& val)
{
ValType type;
type = static_cast<ValType>(val);
}

int main()
{
MyType a;
setType<complex<double> >(a);
return 0;
}

bood
21st April 2006, 05:19
type = val.operator ValType();

Codes above does not work coz `ValType` here is a qulified name, so it's looked up only in the scope of val, i.e. MyType, so the `typename ValType` declared in the template function won't be looked up. But I haven't seen any solutions by now...:(



type = static_cast<ValType>(val);

However, it's weired that gcc3.4.2 reports an ambiguous. Gcc says there are two candidates:


std::complex<double>::complex(const std::complex<double>&)
and
std::complex<double>::complex(double, double)

But the second one has two arguments, how can it beambiguous? I cannot understand why...

bitChanger
21st April 2006, 15:48
If you look at the 2 candidates that it provides you'll notice that they are constructors for the std::complex class. The compiler is confused and don't even see the conversion operator in this case.

jacek
21st April 2006, 16:36
Then maybe something like this:
class MyType
{
public:
MyType() {}
~MyType() {}

template< typename T > T convertTo() const;
};

template<>
char MyType::convertTo< char >() const { return 'a'; }

template<>
int MyType::convertTo< int >() const { return 1; }

...

template<>
complex< double > MyType::convertTo< complex< double > >() const
{
return complex< double >( 1.0, 1.0 );
}

template< typename ValType >
void setType( const MyType& val )
{
ValType type;
type = val.template convertTo< ValType >();
}