By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,136 Members | 1,205 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,136 IT Pros & Developers. It's quick & easy.

(Templated) Operator overload on return type.

P: n/a
Hi,

I belive what i am trying to do is not possible, but I hope someone can
change my mind.

Here is some code i'd like to write:

template <class type> class engine1 {};
template <class type> class engine2 {};

template <template <class> class engine, class type>
class optest : public engine<type> {

public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

type data;
};

template <
template <class> class engine, // This isn't legal
template <class> class engine1,
template <class> class engine2,
class type

const optest<engine, type> operator*(
const optest<engine1, type>& op1,
const optest<engine2, type>& op2) {
optest<engine, type> res;
res.data = op1.data * op2.data;
return res;
}

typedef optest<engine1, int> A1;
typedef optest<engine2, int> A2;

int main() {

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = a1 * a1;
a2 = a2 * a2;

a1 = a1 * a2;
a2 = a2 * a1;

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = a2 * a1;
a2 = a1 * a2;

// ... how can I do this, at all?
a1 = a2 * a2;
a2 = a1 * a1;

return 0;
}

Is there a way, to do this without conversions. (Becuase these would be
expensive, in the real project).

TIA

Fabio


Sep 8 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
"Fabio Fracassi" <f.********@gmx.net> wrote in message
news:df*************@news.t-online.com
Hi,

I belive what i am trying to do is not possible, but I hope someone
can change my mind.
The issue below isn't actually overloading; it is template argument
deduction. But, as with overloading, you can't do it on return type. There
is at least one alternative, however.

Here is some code i'd like to write:

template <class type> class engine1 {};
template <class type> class engine2 {};

template <template <class> class engine, class type>
class optest : public engine<type> {

public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

type data;
};

template <
template <class> class engine, // This isn't legal
It is legal. It is just that the compiler is unable to deduce engine from
the object to which you are assigning the result of the operator. This means
you have to specify it explicitly. See below.
template <class> class engine1,
template <class> class engine2,
class type
>

const optest<engine, type> operator*(
const optest<engine1, type>& op1,
const optest<engine2, type>& op2) {
optest<engine, type> res;
res.data = op1.data * op2.data;
return res;
}

typedef optest<engine1, int> A1;
typedef optest<engine2, int> A2;

int main() {

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = a1 * a1;
a2 = a2 * a2;

a1 = a1 * a2;
a2 = a2 * a1;

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = a2 * a1;
a2 = a1 * a2;

// ... how can I do this, at all?
a1 = a2 * a2;
a2 = a1 * a1;

return 0;
}

Is there a way, to do this without conversions. (Becuase these would
be expensive, in the real project).


The following compiles (you need the "illegal" line from above). It isn't as
nice to type, but you could use macros/inline functions to make it easier.

int main()
{

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = operator*<engine1>(a1, a1);
a2 = operator*<engine2>(a2, a2);

a1 = operator*<engine1>(a1, a2);
a2 = operator*<engine2>(a2, a1);

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = operator*<engine1>(a2, a1);
a2 = operator*<engine2>(a1, a2);

// ... how can I do this, at all?
a1 = operator*<engine1>(a2, a2);
a2 = operator*<engine2>(a1, a1);

return 0;
}
--
John Carson

Sep 8 '05 #2

P: n/a
John Carson wrote:
"Fabio Fracassi" <f.********@gmx.net> wrote in message
news:df*************@news.t-online.com
Hi,
The issue below isn't actually overloading; it is template argument
deduction. But, as with overloading, you can't do it on return type.
My mistake sorry.
template <class type> class engine1 {};
template <class type> class engine2 {};

template <template <class> class engine, class type>
class optest : public engine<type> {

public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

type data;
};

template <
template <class> class engine, // This isn't legal


It is legal. It is just that the compiler is unable to deduce engine from
the object to which you are assigning the result of the operator. This
means you have to specify it explicitly. See below.


Yes, of course. Sorry.
The following compiles (you need the "illegal" line from above). It isn't
as nice to type, but you could use macros/inline functions to make it
easier.

a1 = operator*<engine1>(a2, a1);


Yes, but this would somehow defy the purpose of operator overloading,
wouldn't it? I will have to check if expression templates could help here.

Thanks

Fabio




Sep 8 '05 #3

P: n/a
Fabio Fracassi wrote:
Hi,

I belive what i am trying to do is not possible, but I hope someone can
change my mind.

Here is some code i'd like to write:

template <class type> class engine1 {};
template <class type> class engine2 {};

template <template <class> class engine, class type>
class optest : public engine<type> {

public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

type data;
};

template <
template <class> class engine, // This isn't legal
template <class> class engine1,
template <class> class engine2,
class type
> const optest<engine, type> operator*(
const optest<engine1, type>& op1,
const optest<engine2, type>& op2) {
optest<engine, type> res;
res.data = op1.data * op2.data;
return res;
}


These template parameter names used here are confusingly similar to the
class names also in use by the program. It might clarify matters to
declare the operator routine more distinctly:

template <
template <class> class E, // how to determine E?
template <class> class E1,
template <class> class E2,
class T const optest<E, T>
operator*( const optest<E1, T>& op1,
const optest<E2, T>& op2 )
{
optest<E, type> res;

res.data = op1.data * op2.data;
return res;
}
typedef optest<engine1, int> A1;
typedef optest<engine2, int> A2;

int main() {

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = a1 * a1;
a2 = a2 * a2;

a1 = a1 * a2;
a2 = a2 * a1;

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = a2 * a1;
a2 = a1 * a2;

// ... how can I do this, at all?
a1 = a2 * a2;
a2 = a1 * a1;

return 0;
}

Is there a way, to do this without conversions. (Becuase these would be
expensive, in the real project).


The first task to get this code to compile is to supply the missing
information. Namely, when mutliplying a type A1 object with a type A2
object, what is the type of the resulting product? Will it be of type
A1 or type A2 or some other type completely?

For the sake of discussion let's say the product's type is always the
same type as the lefthand operand:

template <
template <class> class E1,
template <class> class E2,
class T>
const optest<E1, T>
operator*( const optest<E1, T>& op1,
const optest<E2, T>& op2)
{
optest<E1, type> res;

res.data = op1.data * op2.data;
return res;
}

However the program also wants to be able to assign the product to a
variable of the righthand type:

a2 = a1 * a2;

To do so, optest needs to supply a template assignment operator (and
also a converting constructor, but I can't do all the work) in order
for the above statement to compile:

template <
template <class> class engine,
class type>
class optest : public engine<type>
{
public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

template <
template <class> class E, class T >
optest&
operator=( const optest<E, T>& op1 )
{
data = op1.data;
return *this;
}
type data;
};

Now, the sample code provided compiles correctly.

Greg

Sep 9 '05 #4

P: n/a
Greg wrote:
Fabio Fracassi wrote:
Hi, Is there a way, to do this without conversions. (Becuase these would be
expensive, in the real project).

What I wrote above is important! In my real project the class in question
contain (sometimes big, i.e > 1mb) images, so ...
template <
template <class> class E, class T >
optest&
operator=( const optest<E, T>& op1 )
{
data = op1.data;
.... this extra copy of data is a real problem.
return *this;
}
type data;
}; Greg


As I already said in my reply to John, I will probably use some kind of
expression templates, which will also help when using more than one
operator in one expression.

Anyway thanks,

Fabio


Sep 9 '05 #5

P: n/a
Fabio Fracassi wrote:
Greg wrote:
Fabio Fracassi wrote:
Hi, Is there a way, to do this without conversions. (Becuase these would be
expensive, in the real project).


What I wrote above is important! In my real project the class in question
contain (sometimes big, i.e > 1mb) images, so ...
template <
template <class> class E, class T >
optest&
operator=( const optest<E, T>& op1 )
{
data = op1.data;


... this extra copy of data is a real problem.
return *this;
}
type data;
};

Greg


As I already said in my reply to John, I will probably use some kind of
expression templates, which will also help when using more than one
operator in one expression.


You're barking up the wrong tree. Every one of your statements already
creates a copy of the data in a temporary variable and assigns it to
the left hand expression. Copying an A1 object into A2 object with a
programmer-supplied assignment operator is just as efficient (if not
more so) than any of the other copy expressions. The only difference
between:

a1 = a1 * a1;

and

a2 = a1 * a1;

is the that in the first the compiler writes the assignment operator
that copies the right hand expression into a1, while in the second the
programmer has to write the assignment operator to copy the same result
into a2. Otherwise there is no meaningful difference. So if the first
statement is reasonably efficient, then the second one using an
implementation-provided assignment operator, must be as well.

Furthermore if copy operations for these classes are so costly, then
none of the assignment statements in the sample code are reasonable.
But as a practical matter, large data structures should not be held by
value, but should be held indirectly, usually through a shared pointer
as a data member. The class holding the data should have well-thought
out copy semantics. A class whose copy semantics have been thought
through is one that either implements the proper constructor and
assignment operators for copyable types, or declares them private.
After all, data management is often too important to leave up to the
compiler-written routines (which are not even visible in the source
code) to handle.

Greg

Sep 9 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.