Problem with implicit conversion

B

Boris

Hello,

I have written a program that compiles just fine with GCC 3.3. With
GCC 3.4.1 it results in this error:

g++ -O0 -g3 -Wall -c -oTestp.o ../Testp.c
.../Testp.c: In function `int main()':
.../Testp.c:26: error: no match for 'operator<=' in 't <= 2.0e+0'

Please help me, I have no idea where the problem is.

Here is the code:

template <class T> class BasisF;

template <class T> inline bool operator<=(const BasisF<T> &a, const
BasisF<T> &b){return a.x <= b.x;}

template<class T> class BasisF{

public:
T x;
BasisF(const T &_x = T()): x(_x){}
BasisF(const BasisF &_b): x(_b.x){}
~BasisF(){}
BasisF& operator= (const T &_x){
x = _x;
return *this;
}
friend bool operator<=<>(const BasisF &a, const BasisF &b);
};

#define min(a,b) ((a) <= (b) ? (a) : (b))

int main(){
BasisF<double> t(1);
if (min(t,2.0)<=0) return 1;
return 0;
}

Regards,
Boris
 
R

Rob Williscroft

Boris wrote in in
comp.lang.c++:
I have written a program that compiles just fine with GCC 3.3. With
GCC 3.4.1 it results in this error:

g++ -O0 -g3 -Wall -c -oTestp.o ../Testp.c
../Testp.c: In function `int main()':
../Testp.c:26: error: no match for 'operator<=' in 't <= 2.0e+0'

Please help me, I have no idea where the problem is.

The problem is that double isn't an exact match for a deducable
paramiter:

template <class T> class BasisF;

/* Prevent the compiler from triing to deduce T from the second
argument, and force the conversion.
*/
template < typename T > struct identity { typedef T type; };

template <class T>
inline bool operator <= (
BasisF<T> const &a,
typename identity< BasisF<T> >::type const &b
)
{
return a.x <= b.x;
}

template<class T>
class BasisF
{
public:
T x;
BasisF( T const &_x = T() ) : x( _x) {}
BasisF(BasisF const &_b) : x( _b.x ) {}
~BasisF() {}
BasisF& operator= (T const &_x)
{
x = _x;
return *this;
}
};

#define min(a,b) ((a) <= (b) ? (a) : (b))

int main()
{
BasisF<double> t(1);

/* Note only 0, EXIT_SUCCESS and EXIT_FAILURE (both from <cstdlib>) are
standard (portable) return values for main().
*/
if (min(t,2.0)<=0) return 1;

return 0;
}

The problem with the above is 0.0 <= BaseF< double >( 0.0 ) doesn't work.

Here's a version that does:

template <class T> class BasisF;

/* Boilerplate
*/
template < typename Left, typename Right >
struct BasisF_comp_enable
{
};

template < typename T >
struct BasisF_comp_enable< BasisF< T >, BasisF< T > >
{
/* enable_if return type
*/
typedef bool bool_type;

/* actual type to compare
*/
typedef BasisF< T > comp_type;
};

/* Left handed version
*/
template < typename T >
struct BasisF_comp_enable< BasisF< T >, T >
{
typedef bool bool_type;
typedef BasisF< T > comp_type;
};

/* Rhight handed version
*/
template < typename T >
struct BasisF_comp_enable< T, BasisF< T > >
{
typedef bool bool_type;
typedef BasisF< T > comp_type;
};

template < typename Left, typename Right >
inline typename BasisF_comp_enable< Left, Right >::bool_type
operator <= ( Left const &left, Right const &right )
{
typedef typename BasisF_comp_enable< Left, Right >::comp_type type;

type const &lhs = left;
type const &rhs = right;

return lhs.x < rhs.x;
}

template<class T>
struct BasisF
{
T x;
BasisF( T const &_x = T() ) : x( _x) {}
};


#include <iostream>
#include <ostream>
#include <iomanip>

int main()
{
using namespace std;

BasisF<double> t(1);

cout << boolalpha << ( t <= 2.0 ) << '\n';
cout << boolalpha << ( 0.0 <= t ) << '\n';
}

There is a lot of boilerplate above, but you can presumably
reuse it for other operators, but check out the links bellow.

links:

http://boost-consulting.com/boost/libs/utility/enable_if.html

<http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8
&q=restrict_to+group%3Acomp.*+author%[email protected]>

aka: http://tinyurl.com/5kh86

Rob.
 
V

Victor Bazarov

Boris said:
I have written a program that compiles just fine with GCC 3.3. With
GCC 3.4.1 it results in this error:

g++ -O0 -g3 -Wall -c -oTestp.o ../Testp.c
../Testp.c: In function `int main()':
../Testp.c:26: error: no match for 'operator<=' in 't <= 2.0e+0'

Please help me, I have no idea where the problem is.

Here is the code:

template <class T> class BasisF;

template <class T> inline bool operator<=(const BasisF<T> &a, const
BasisF<T> &b){return a.x <= b.x;}

template<class T> class BasisF{

public:
T x;
BasisF(const T &_x = T()): x(_x){}
BasisF(const BasisF &_b): x(_b.x){}
~BasisF(){}
BasisF& operator= (const T &_x){
x = _x;
return *this;
}
friend bool operator<=<>(const BasisF &a, const BasisF &b);

You don't need this friend declaration, 'x' is public.
};

#define min(a,b) ((a) <= (b) ? (a) : (b))

Ugh! If you are starting with templates, shouldn't you be getting rid of
all macros of that sort?
int main(){
BasisF<double> t(1);
if (min(t,2.0)<=0) return 1;
return 0;
}

The compiler can't figure out what 'T' should be for the ::eek:perator<=
template (from the macro expansion) because one is 'BasesF<double>' and
the other is 'double'. It will not look for a conversion from those
types to some kind of common type and then use it as 'T'.

To solve it you need to add two more operators,

template<class T> bool operator<=(const BasisF<T>& a, const T& b)
{
return a.x <= b;
}

and

template<class T> bool operator<=(const T& a, const BasisF<T>& b)
{
return a <= b.x;
}

and then use literals of type 'double' to make your compiler resolve
the operators correctly. Otherwise, you could do

template<class T, class U>
bool operator<=(const T& a, const U& b)
{
return BasisF<T>(a).x <= BasisF<U>(b).x;
}

Victor
 
M

Marc

Boris said:
BasisF(const T &_x = T()): x(_x){}

The automatic transformation of a double or an int into a BasisF does
not work as you think it does.
friend bool operator<=<>(const BasisF &a, const BasisF &b);

Do you have a particular reason to want this operator as a friend
fonction rather than a member function?
if (min(t,2.0)<=0) return 1;

You could explicit BasisF<double>(0) instead of 0 and the same for 2.0,
if you do not want to make <= a member function or explicitly overload
<= for BasisF<double> and double.
 

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

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top